這篇主要是為我自己做紀錄的,每次想到 http 這幾個版本的差異,總是有幾項會忘記…
我會盡可能的每當看到哪個版本有這篇沒記錄到的內容時,更新這篇。
HTTP/1.0:
- keep-alive 需手動開啟,僅支持短暫的 TCP 連接。
- 隊頭阻塞 (Head-Of-Line Blocking): 前一個請求響應到達之後,下一個才能請求才能發送,故前一個阻塞,後面全阻塞。
- 強緩存:
expires
。 - 協商緩存:
last-modified
(response) /if-modified-since
(request)。
HTTP/1.1:
- 長連接 (keep-alive) 預設開啟,可復用 TCP 連接,持續保持一段時間 (timeout),但同一時間只能對應一個 http 請求。
若兩小時 (timeout) 沒有收到 client 端數據,server 會發送一個探測報文,之後每隔 75 秒發送一次,若接連發送 10 個後仍無回應,server 會判斷 client 端出現故障,來關閉這個連接。 - Pipelining (管道化): 串行傳輸,默認不開啟,可以不等第一個請求響應就繼續發送請求,但響應順序依然依請求順序,故依然有隊頭阻塞問題。
- 文本傳輸。
- 添加強緩存:
cache-control
。 - 添加協商緩存:
etag
(response) /if-none-matched
(request)。 - 斷點傳輸: 在上傳/下載時,若資源過大,將其分割多個部分,分別上傳/下載,若遇到網路故障,可以從已經上傳/下載好的地方繼續請求,不用從頭開始。
HTTP/2.0:
- 壓縮了 header,演算法為 HPACK。
- 多路復用 (MultiPlexing): 一個 TCP 中,多個 http 請求是併行的,每個 request 對應一個 ID,server 根據 request ID 將消息重新組裝。
- 可以設置 request 優先級,0 為最優先,數字越大優先級越低。
- 二進制編碼傳輸: 每個 http 請求報文會被切片成 frame,用來傳輸的 TCP 通道稱為 stream;不同的 frame 在 stream 裡面傳輸,每個 frame 會被壓縮為二進制。
- server push。
- websocket。
- 缺點: HTTP/2 也存在隊頭阻塞,比如丟包。若發生隊頭阻塞,問題比 HTTP/1.1 嚴重,因只有一個 TCP 連接。
HTTP/3.0:
- 使用 QUIC (Quick UDP Internet Connections) 。
QUIC 在移動端上,表現比 TCP 好,因為 TCP 是基於 IP 和端口進行識別,在多變的移動端網路環境下很脆弱。
但 QUIC 是通過 ID 去識別一個連接,故即使網路環境變更,只要 ID 沒變,就能迅速重新連上。 - 使用 TLS 1.3 加密。
- 非首次連接僅 0 RTT。
- 多路復用: HTTP/2 雖支持,但 TCP 協議終究沒這個功能。而 QUIC 實現了此功能。
- 向前糾錯機制 (Forward Error Correction, FEC): 每個數據包除了本身的內容外,還包含部份其他數據包內容,因此少量的丟包,可以通過其他包的冗餘數據直接組裝,而無需重傳。
因重傳更花時間,包含確認數據包丟失、請求重傳、等待新數據包等步驟。
其他補充
Pipelining:
- 用同一個通道:
request 1 > response 1 → request 2 > response 2 → request 3 > response 3
- 管道化:
request 1 → request2 → request 3 > response 1 → response 2 → response 3
keep-alive 與多路復用差別:
- keep-alive 必須按照 request 順序返回 response;多路復用無需按順序。
- keep-alive 為避免隊頭阻塞,將同一頁面的資源分散到不同的域名下,開啟多個 TCP 連接;多路復用在同個域名下,所有通信都在一個連接上完成。
為什麼 HTTP/1.1 無法使用多路復用?
HTTP/1.1 不是二進制傳輸,而是文本傳輸。由於沒有 stream 概念,在使用併行傳輸 (多路復用) 時,接收端在接收到響應後,無法區分多個響應對應的請求,所以無法將多個響應的結果進行組裝,也就實驗不了多路復用。