這個問題只存在用戶端是IE或IE核心的情況,但是你無法控制用戶端使用什麼瀏覽器,所以仍然會給你的應用造成很大的效能問題。
我們先說現象:
服務端:我們只用一個靜態HTML頁面ok.html,內容只返OK.
然後我們寫一個ajax調用的html在用戶端訪問:
<script>function send_request(method,url,param) { http_request = false; if (window.XMLHttpRequest) { http_request = new XMLHttpRequest(); } else if (window.ActiveXObject) { try { http_request = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { http_request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { } } } if (!http_request) { return; } http_request.open(method, url,true); http_request.send(param);}function get(){ var url = "http://myhost/ok.html?name=axman&test=123"; for(var i=0;i<1000;i++){ send_request("GET",url,null); }}function post(){ var url = "http://myhost/ok.html"; for(var i=0;i<1000;i++){ send_request("POST",url,'name=axman&test=123'); }}</script><input type="button" name="b1" value="get" onclick="get()"><input type="button" name="b2" value="post" onclick="post()">
這個頁面上兩種方式訪問和傳遞的參數完全一致,當我按下get按鈕後,服務端收到了1000個訪問記錄。
[admin@vm-platform access_log]$ cat apache_access.log.4 |wc -l
1000
然後我統計訪問時間大於1ms的記錄:
[admin@vm-platform access_log]$ cat apache_access.log.4 |awk '{if($12 > 1000) print $0}'
結果是空。
現在我們再按下POST按鈕:
[admin@vm-platform access_log]$ cat apache_access.log.4 |wc -l
2000
當服務端顯示2000時,說明訪問完成。
[admin@vm-platform access_log]$ cat apache_access.log.4 |awk '{if($12 > 1000) print $0}'的結果:
10.16.14.82 - - - [24/Nov/2011:16:08:55 +0800] "POST /myhost/ok.html HTTP/1.1" 200 20 696078 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)" - - "a=-; b=-; c=-" -
10.16.14.82 - - - [24/Nov/2011:16:08:55 +0800] "POST /myhost/ok.html HTTP/1.1" 200 20 696045 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)" - - "a=-; b=-; c=-" -
10.16.14.82 - - - [24/Nov/2011:16:08:55 +0800] "POST /myhost/ok.html HTTP/1.1" 200 20 695776 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)" - - "a=-; b=-; c=-" -
10.16.14.82 - - - [24/Nov/2011:16:08:55 +0800] "POST /myhost/ok.html HTTP/1.1" 200 20 695332 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)" - - "a=-; b=-; c=-" -
10.16.14.82 - - - [24/Nov/2011:16:08:55 +0800] "POST /myhost/ok.html HTTP/1.1" 200 20 696500 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)" - - "a=-; b=-; c=-" -
10.16.14.82 - - - [24/Nov/2011:16:08:55 +0800] "POST /myhost/ok.html HTTP/1.1" 200 20 696484 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)" - - "a=-; b=-; c=-" -
10.16.14.82 - - - [24/Nov/2011:16:08:55 +0800] "POST /myhost/ok.html HTTP/1.1" 200 20 696215 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)" - - "a=-; b=-; c=-" -
10.16.14.82 - - - [24/Nov/2011:16:08:55 +0800] "POST /myhost/ok.html HTTP/1.1" 200 20 696235 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)" - - "a=-; b=-; c=-" -
10.16.14.82 - - - [24/Nov/2011:16:08:55 +0800] "POST /myhost/ok.html HTTP/1.1" 200 20 696182 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)" - - "a=-; b=-; c=-" -
10.16.14.82 - - - [24/Nov/2011:16:08:55 +0800] "POST /myhost/ok.html HTTP/1.1" 200 20 694964 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)" - - "a=-; b=-; c=-" -
10.16.14.82 - - - [24/Nov/2011:16:08:58 +0800] "POST /myhost/ok.html HTTP/1.1" 200 20 1274 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)" - - "a=-; b=-; c=-" -
10.16.14.82 - - - [24/Nov/2011:16:08:59 +0800] "POST /myhost/ok.html HTTP/1.1" 200 20 1019 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)" - - "a=-; b=-; c=-" -
請注意apache %D記錄的時間是從第一個頭域(讀到第一個換行斷行符號開始)記時到響應輸出(協議層,只要寫到BUFF中,不一定已經發送到用戶端)。這個時間單位是
微秒,請看一下其中有10條記錄近700ms,是get方式的千倍。
因為這個現象給我們的兩個應用帶來效能問題,我開始分析這個原因,後來從網上搜尋到文章說IE核心的瀏覽器在AJAX調用時,對POST方式採用兩步發送,第一次發送
頭域,第二次發送BODY。中間有很大的延遲,有時還會造成BODY包丟失,我們從網路抓包的情況看,確實存在只發送了HEADER,後面只有服務端逾時返回的錯誤資料包,再也沒有BODY的資料。這樣的機率大約有1%.
這個問題在apache作為proxy時,proxy就不能在有效時間內將用戶端請求發送給backend,造成大量的內部錯誤輸出。如果是SS還會引起資料時序混亂。在發送\r\n\r\n後頭域還有尾巴沒有發送完成,這些現象都是從網路抓包監控到的。
如果換成fireFox,同樣的AJAX代碼執行POST就沒有問題,關鍵是你根本無法控制使用者不使用IE。
網上給出的解決方案試了一下根本不起作用(也許IE6可以起作用,我用的IE8就沒有細測IE6),關鍵是只要部分瀏覽器發生這個情況,就會給應用帶來很大的效能問題。
所以盡量少使用AJAX的POST方式提交資料,但是有時服務端為了安全的原因只允許POST提交,可以動態構造FORM表單,而盡量少使用AJAX來調用POST。