10

IE AJAX 呼叫發生 0x2ee2 錯誤

 3 years ago
source link: https://blog.darkthread.net/blog/ie11-unsent-xhr-request-timeout/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

IE AJAX 呼叫發生 0x2ee2 錯誤

calendar.svg 2021-09-10 11:59 PM comment.svg 1 eye.svg 512

同事報案,有個網頁會一次發出大量 AJAX 呼叫再蒐集回應,今有某個極端案例同時丟出 600 筆資料,在 IE 發生「SCRIPT7002: XMLHttpRequest: 網路錯誤 0x2ee2, 發生錯誤,無法完成操作 00002ee2。」錯誤,但在 Chrome/Edge 則不會出錯。

先補上背景知識,瀏覽器對每個伺服器 IP 的同時 HTTP 連線是有上限的,依經驗 IE11 最大連線數為 10、Chrome 則是 6。意思即時同時對同一台網站發出 20 個非同步 XHR 請求,最多只會有 10 條連線,第 11 個請求要等前面 10 個任何一個結束釋出連線才會送出。參考:IE MaxConnectionsPerServer 參數效果實測

我設計一段測試程式可以重現這個問題。ASP.NET 程式在前端同時丟出 800 個 AJAX POST 請求,後端處理時則故意 Delay 5 秒再回應 OK 以造成塞車現象:

<%@ Page Language="C#" %>
<script runat="server">
void Page_Load(object sender, EventArgs e)
{
	if (Request.HttpMethod == "POST") 
	{
		System.Threading.Thread.Sleep(5000);
		Response.Write("OK");
		Response.End();
	}
}
</script>
<!DOCTYPE html>
<head>
	<meta charset="utf-8">
</head>
<body>
	<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
	<script>
	function getCallbackFunc(n) {
		return function() {
			console.log(new Date().toISOString().substr(14,5) + " Response-" + n);
		}
	}
	for (var i = 0; i < 800; i++) {
		$.post("MaxXhrConn.aspx").done(getCallbackFunc(i));
	}
	</script>
</body>
</html>

一如預期,由於最多同時只能有 10 條連線,800 個 AJAX POST 會以每五秒 10 個的速度消化:

然後,800 個 XHR 苦等 10 條連線,觀察等待超過 300 秒的請求便會失敗噴出「SCRIPT7002: XMLHttpRequest: 網路錯誤 0x2ee2, 發生錯誤,無法完成操作 00002ee2。」錯誤:

由 F12 開發者工具網路傳輸記錄,成功呼叫中耗時最長為 305.33 秒,其中「正在連線(TCP)」時間為 299.12 秒,即因連線數達到上線的等待時間,而「正在等侯(TTFB)」則為 ASPX 端 Delay 5 秒再回傳的時間。

同樣程式在 Chrome/Edge 執行則不會出錯(其最大連線數為 6):

總等待時間長達 11 分鐘半仍可完成:

查到 Stackoverflow 有人反映相同問題 - 在 IE11 等待 5 分鐘還沒有送出的 XHR 請求會拋出 0x2ee2 錯誤,而這個 5 分鐘等待上限與 XHR.timeout 無關,是 IE 獨有的限制,似乎也無從調整。

網路上有一派解法是放大 IE MaxConnectionsPerServer 參數增加連線數,其原理相當於加開櫃檯減少排隊時間不要超過 5 分鐘,但這畢竟是治標做法,只要伺服器端處理慢到一定程度將所有連線卡死,排隊時間仍有可能逾時。較好的做法是改變前端程式寫法,自己控制發出 AJAX 呼叫的時機及數量,我們可以比照 .NET 控制執行緒數目的做法,將所有待辦工作放進 Queue,用 setTimeout 同時跑六個 while 迴圈,每個迴圈 Queue 取出待辦項目發出 AJAX 請求,做完再處理下一個,如此即可精準控制最多只會用到 6 條連線。

又學到一些新東西。

  • Posted in
  • IE
and has 1 comment

Comments

Post a comment

Comment
Name Captcha 84 - 29 =

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK