ie瀏覽器F12查看請求掛起

只有在IE(目前只在IE8和IE9中測試)中瀏覽時,發現有好些資源加載不上,在F12工具裏查看發現是請求被掛起,一段時間後就會終止,(此時的IE的請求並不多),在HttpWatch裏查看這種請求,是大約30秒後就會有異常:Error_internet_connection_reset,同樣的應用用火狐或者谷歌一切正常,如圖。但是另一個奇怪的現象是,如果在局域網內網訪問這個應用的話,一切又正常了——這尼瑪是要弄死我的節奏


IE下Ajax請求偶發12152連接超時錯誤淺析
昨天被分到一個Bug,公司某產品在IE下偶爾會隨機出現請求掛起,等待30秒後彈出超時錯誤(錯誤狀態碼:12152)的問題,而在FireFox或Chrome則從沒有這樣的問題。據說這個問題已經困擾他們四年多了,一直混着。直到最近在某個大客戶的新環境中頻頻出現,纔不得不專門找人( )解決。接到這個Bug,感覺就是某個經典的IE Repost問題,之前一直沒有機會詳細瞭解,借這個機會翻了一些資料,在這裏總結一下。

產生原因
現在的HTTP連接,特別是HTTPS連接,爲了提高性能,幾乎全部採用Keep-Live模式。也就是連接建立起來後會存活一段時間(數秒到數十秒不等),這段時間內的請求會重用這個連接。根據HTTP 1.1 (RFC 2616)標準,連接路徑上的代理服務器,負載均衡服務器,應用服務器等節點都可以隨時中止這個連接。一般情況下如果網速較快,連接被中止時瀏覽器會立刻知道,下一個請求就建立新連接,不會出現明顯問題。但在網速不佳的環境中,會出現一種邊界場景:瀏覽器發出了一個請求,但在請求還沒到服務器前,服務器端認爲連接超時,中止了連接。這時瀏覽器會立刻得到一個請求超時錯誤,根據RFC 2616標準,瀏覽器這時應該無須用戶干預,自動重新建立新的連接並且重發之前的請求。各大瀏覽器都遵循了這個規範,因此在FireFox或Chrome下,用戶根本不會意識到有Keep-Live連接超時這回事。

引用

原文如下:
A client, server, or proxy MAY close the transport connection at any time. For example, a client might have started to send a new request at the same time that the server has decided to close the "idle" connection. From the server's point of view, the connection is being closed while it was idle, but from the client's point of view, a request is in progress.

This means that clients, servers, and proxies MUST be able to recover from asynchronous close events. Client software SHOULD reopen the transport connection and retransmit the aborted sequence of requests without user interaction so long as the request sequence is idempotent (see section 9.1.2).


但,IE的XMLHttpRequest實現(某COM組件)在重發請求時有個低級錯誤:只會重發header部分,而忘了重發原來請求的內容部分!並且,在header中,仍然包含了原來請求中的content length (內容大小)數據。服務器在接收到這個請求header後,就開始望眼欲穿地等待指定大小的請求內容,而IE根本不會繼續發送任何內容。於是,一段時間後,用戶收到了一個真正的連接超時錯誤。

這個問題,根據微軟官方文檔,確認在IE6-9中都存在,IE10和後續版本到底如何(以及IE10的兼容模式下到底如何),我暫時還沒找到明確文檔。

如果你已經開始驚歎IE的弱智,別急,這只是開胃菜,更無厘頭的在後面。

微軟在收到用戶投訴後,發了一個hotfix ( http://support.microsoft.com/kb/895954/en-us ),題目翻譯過來大概是《當你使用IE或其他程序重發post請求時,只有請求頭會被髮送》,全文沒有任何一處提到12152錯誤碼和上面的錯誤現象。最開始也不知道是哪位天才把上述問題和這個hotfix聯繫起來的。

在IE6下,用戶需要下載安裝這個hotfix。而IE7-9,則已經內置了這個hotfix。但是————這個hotfix默認是禁用的,用戶需要手動在註冊表中添加一個名爲 FEATURE_SKIP_POST_RETRY_ON_INTERNETWRITEFILE_KB895954 ( !!!!) 的項目來開啓它。具體操作可以參考 http://support.microsoft.com/kb/895954/zh-cn 的《如何啓用此修補程序》一節,複製如下:

引用

如何啓用此修補程序

警告如果使用註冊表編輯器或其他方法錯誤地修改了註冊表,可能會出現嚴重問題。這些問題可能要求您重新安裝操作系統。Microsoft 不能保證這些問題能夠得到解決。修改註冊表的風險由您自己承擔。

若要添加此註冊表值,請執行以下步驟:
1. 單擊開始,單擊運行,鍵入regedit,然後單擊確定

2. 找到並單擊以下註冊表子項之一。管理客戶端計算機的相應子項使用所指定的策略。

  * HKEY_CURRENT_USER\Software\Policies\Microsoft\Internet Explorer\Main\FeatureControl
  * HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\FeatureControl
  * HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Internet Explorer\Main\FeatureControl
  * HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Main\FeatureControl

3. 在編輯菜單上,單擊新建,然後單擊項。
鍵入FEATURE_SKIP_POST_RETRY_ON_INTERNETWRITEFILE_KB895954作爲子項的名稱,然後按 enter 鍵。
4. 單擊FEATURE_SKIP_POST_RETRY_ON_INTERNETWRITEFILE_KB895954子項。
5. 在編輯菜單上,指向新建,然後單擊DWORD 值。
6. 爲 dword 值名稱中,鍵入* ,然後按 enter 鍵。
7. 用鼠標右鍵單擊*,然後單擊修改。
8. 在數值數據框中,鍵入00000001,然後單擊確定。
9. 退出註冊表編輯器。


網上很多人摸不着頭腦,這麼低級且惡劣的問題,明明出來一個hotfix,後期都直接內置了,幹嘛不默認打開,還搞得這麼複雜。其實,微軟的文檔裏沒有說他們是如何修復這個錯誤的,一旦你真的開啓了hotfix,就豁然開朗了。正如這個古怪的註冊表項目名稱所說的,微軟“修復”這個錯誤的做法是:Skip Post Retry!!!! 沒錯,他們不是把重發請求的問題改好,而是直接不重發了!!!!所以,你開啓fix後,會偶爾直接得到一個12152錯誤,而不用等30秒了,問題解決,OH YEAH。

解決方案探討

網上有一些討論說可以通過在相應的請求頭中加入Connection:close通知瀏覽器每次都關閉連接解決此問題,或者通過在服務器中提高Keep-Live的timeout時間來緩解問題。但一些資料說明,這類方案有一下問題:

1. 某些服務器並不理會請求頭中關於連接的設定,程序員需要手工添加一些關閉連接的代碼。我發現多數直接加入Connection:close的成功案例都是PHP的,估計跟PHP直接架在Apache上有關。

2. 如果你選擇提高timeout,你需要把從用戶瀏覽器到你服務器的物理連接路徑上所有忽略請求頭連接設置的節點都手工設置好。(對我們公司的實際場景來說幾乎不可能)

3. 每次重新創建連接的性能損耗頗大(有人說很大,有人說沒感覺,具體多少我沒試過,因爲上面1,2已經把我踢出局了)

微軟的意圖很明顯,要麼你可以繼續默認關閉hotfix,IE會非常配合地給用戶一個無可挑剔的服務器超時假象,然後你可以跟客戶說,你們的防火牆不穩定,自己檢討一下吧。 要麼你可以讓客戶開啓hotfix,然後自己在應用中實現一個重試機制,我這兩天就在幹這件事。

最後一件噁心的事:這個Keep-Live連接timeout和普通timeout都使用12152錯誤碼,拜託IE你都出hotfix了,意圖這麼明顯是讓程序員自己解決,你至少也弄個標誌讓我分辨出哪個是需要在應用中重發的timeout吧。目前我採用的方案是,在請求前記錄時間,如果出現12152錯誤且等待時間小於5秒,則認爲是Keep-Live連接超時,由應用主動重發請求。

也許最好的方案是,說服客戶不要用IE。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章