
HTTP/1.0、HTTP/1.1 跟 HTTP/2 之間到底差在哪?
前面完成 DNS、TCP 與 TLS 後,瀏覽器終於可以開始交換 HTTP message。不過,同樣是傳送 request 與 response,HTTP/1.0、HTTP/1.1 和 HTTP/2 使用連線的方式卻不太一樣。
先講一下,如果網站目前還只支援 HTTP/1.1,可以評估升級到 HTTP/2。對有許多資源請求的網站來說,HTTP/2 的 multiplexing 通常能減少請求之間互相等待的時間,對網站效能很有幫助。
也因為 HTTP/2 改善了多個請求共用連線的方式,原本為了減少請求數量而採用的某些優化,例如雪碧圖,就不一定還有同樣的效益了。不過要不要保留,還是得看資源大小、快取策略與網站情境!
HTTP/1.0
在 HTTP/1.0 的時代中,網頁會需要建立許多連線後才能組成完整畫面,也就是說每次發出 request 前都要先建立 TCP connection,收到 response 後便關閉連線。下一個 request 又會重新建立一次連線,實際效果像下圖這樣:
也就是說,取得網站所需的資源時,光是重複建立 TCP connection 就會增加不少等待時間。雖然部分 HTTP/1.0 實作後來也支援非標準的 Keep-Alive 機制,但預設行為仍是完成一組 request 與 response 後便關閉連線。
HTTP/1.1
在 HTTP/1.1 中,預設會使用 persistent connection,讓多組 request 與 response 共用同一條 TCP connection。也就是說,不需要每次都重新建立連線、關閉後再重新建立,才能繼續傳輸資料。
HTTP/1.1 也支援 pipelining,讓 Client 不必等前一個 response 回來,就可以先在同一條連線上送出後續 request:
但這裡會有一個問題:雖然 request 可以先送出去,Server 回傳的 response 還是必須依照 request 的順序排列,所以仍然會遇到 head-of-line blocking。
如果第一個 request 需要五秒鐘,而其他 request 只需要一秒,後面的 response 即使先準備好,還是要等第一個 response 回傳後才能繼續傳輸,網頁也就只能繼續等待!
另外,pipelining 是選用機制。如果 Client 沒有使用 pipelining,雖然會沿用同一條 TCP connection,但 Request B 還是要等 Response A 完整回來後才會送出,就像下圖所示:

HTTP/2
到了 HTTP/2,HTTP message 會透過 binary framing layer 傳輸。每一組 request 與 response 都會使用自己的 stream,而 header 與 body 等資料則會被拆成 frame;不同 stream 的 frame 可以在同一條 connection 上交錯傳輸,也就是 multiplexing。
可以把 stream 想成每組 request 與 response 各自的通道:每個資源都先傳一部分資料,瀏覽器收到 frame 後,再依照所屬的 stream 組回完整 message!
這樣一來,Stream B 就不必等 Stream A 的完整 response 傳完,才能繼續接收資料。不過 HTTP/2 的多個 stream 仍共用同一條 TCP connection;如果 TCP 封包遺失,其他 stream 也可能一起等待重傳。因此 HTTP/2 改善的是 HTTP application-layer 的 head-of-line blocking,沒有解決 TCP layer 的 head-of-line blocking。
總結
如果把這三個版本簡單整理,HTTP/1.0 的一般做法是每次 request 都重新建立 TCP connection;HTTP/1.1 預設使用 persistent connection,減少重複建立連線的成本,也能透過 pipelining 先送出多個 request,但同一條連線上的 response 仍必須依序回傳。
HTTP/2 則進一步把 message 拆成 frame,並透過多個 stream 在同一條 connection 上交錯傳輸。這樣不同資源不需要排隊等前一個完整 response 傳完,瀏覽器收到資料後再依照各自的 stream 組回完整 message,通常能讓整體傳輸效率比 HTTP/1.x 更好。
所以 HTTP/2 的重點不只是「共用 TCP connection」,而是能在同一條連線中交錯處理多個 request 與 response,降低 HTTP/1.x 在 application-layer 的等待成本。也因為這個特性,以前為了減少 request 數量而使用的部分優化方式,例如雪碧圖,在 HTTP/2 環境下就不一定還需要使用。
不過 HTTP/2 仍然建立在 TCP 上。當底層 TCP packet 遺失時,多個 HTTP/2 stream 都可能一起等待重傳;後續談到 HTTP/3 與 QUIC 時,就會接著看它如何把 transport-layer 的影響改成以 stream 為單位處理。