瀏覽器發送的 http 請求是復用一個 tcp 連接么


答案

不一定。

發的不同域名,肯定不復用。

發的同域名。若第一個請求與第二個請求並行發送,不復用。

發的同域名,並且是第一個請求完事了才發第二個請求。則看是否有 connection: keep-alive 請求頭,沒有則不復用。

發的同域名,第一個請求完了后發第二個請求,有 connection: keep-alive 請求頭。則復用同一個 TCP 連接。

補充說明

HTTP 1.1 里大概規范了幾項提高性能的手段:

  1. 持久連接 (keep-alive/persistent connection)
  2. 並行連接
  3. Pipelining

持久連接

每一個請求都會重新建立一個 TCP 連接,一旦響應返回,就關閉連接。 而建立一個連接,則需要進行三次握手。HTTP 1.1 出了一個請求頭 connection,默認 keep-alive,告訴服務器不關閉 TCP 連接。

並行連接

由於現代網頁通常包含了復數個(>=10)資源,而按照默認設定,一個連接中的每一個請求必須等待收到響應后才能發送下一個請求,所以如果復數的資源請求全部在一個連接 one by one 發送給服務器顯然會很慢,而為了彌補這一缺陷,瀏覽器通常會默認開啟多個 TCP 連接,然后再根據每個連接的狀態在其中依次發送數據請求,而且客戶端有權任意關閉超發的連接。各個瀏覽器允許的並行連接數大致是這樣的(From SO):

Firefox 2:  2
Firefox 3+: 6
Opera 9.26: 4
Opera 12:   6
Safari 3:   4
Safari 5:   6
IE 7:       2
IE 8:       6
IE 10:      8
Chrome:     6

由於 TCP 協議本身有慢啟動的特征,會隨着時間調諧連接的最大速度,因此在現代瀏覽器中持久連接和並行連接通常是搭配在一起使用的—— 一方面由於持久連接的存在,每個 TCP 連接已經處於調諧后的狀態,另一方面持久連接可以避免重新三次握手的開銷。

在 Chrome 中,頁面初始並行加載一堆靜態資源是會最大開 6 個 TCP 連接去並行運作,其后發 Ajax 請求則是復用之前的 TCP 連接。

Pipelining

按照 HTTP 1.1 的描述,還有種可以提升性能的方案是管道化,可以在一個 TCP 連接中並行執行多個請求並返回。

因為這項技術比較復雜,如何能在一個 TCP 中有序的處理所接收到的包,並且不會亂序返回,這在早期沒有規范,所以各大瀏覽器都沒有支持此功能,形同雞肋。

關於 HTTP 2

HTTP 2 為了性能做了不少努力,比如提供了規范以支持連接的多路復用。

如前文所說,在同一個 TCP 連接里面同時發生兩個請求響應就不是那么簡單。而 HTTP 2 正是提供了這樣的規范,可以給數據拆成包,並打上包的順序標簽以供 TCP 能正確認知接收的包的順序。

所以很多網絡優化的知識已經過時

  • 因為“所有的 HTTP 2.0 的請求都在一個 TCP 鏈接上”,“資源合並減少請求”,比如 CSS Sprites ,多個 JS 文件、CSS 文件合並等手段沒有效果,或者說沒有必要。
  • 因為“多路復用”,采用“cdn1.cn,cdn2.cn,cdn3.cn,打開多個 TCP 會話,突破瀏覽器對同一域名的鏈接數的限制”的手段是沒有必要的。因為因為資源都是並行交錯發送,且沒有限制,不需要額外的多域名並行下載。
  • 因為“服務器推送”,內嵌資源(如base64的圖片)的優化手段也變得沒有意義了。而且使用服務器推送的資源的方式更加高效,因為客戶端還可以緩存起來,甚至可以由不同的頁面共享(依舊遵循同源策略)

參考

你猜一個TCP鏈接上面能發多少個HTTP請求權

HTTP/2.0 簡單總結

瀏覽器向同一域名同時發送兩個 HTTP (ajax)請求,究竟是共用了一個 TCP 連接還是兩個?


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM