總的來說就是HTTP/1.1是請求-響應模型導致隊頭阻塞問題,HTTP2是TCP層面導致隊頭阻塞問題
HTTP/2
多路復用,解決了HTTP/1.1隊頭阻塞問題
HTTP/1.1 的實現是基于請求-響應模型的。同一個連接中,HTTP 完成一個事務(請求與響應),才能處理下一個事務,也就是說在發出請求等待響應的過程中,是沒辦法做其他事情的,如果響應遲遲不來,那么后續的請求是無法發送的,也造成了隊頭阻塞的問題。
HTTP/2 實現了 Stream 并發,多個 Stream 只需復用 1 個 TCP 連接,節約了 TCP 和 TLS 握手時間,以及減少了 TCP 慢啟動階段對流量的影響。不同的 Stream ID 可以并發,即使亂序發送幀也沒問題,比如發送 A 請求幀 1 -> B 請求幀 1 -> A 請求幀 2 -> B 請求幀2,但是同一個 Stream 里的幀必須嚴格有序。
壓縮HTTP頭,節省報文體積
因為大部分HTTP請求的header是重復的,尤其是長長的cookie,通過靜態表和 Huffman 編碼的方式,將體積壓縮了近一半,而且針對后續的請求頭部,還可以建立動態表,將體積壓縮近 90%,大大提高了編碼效率,同時節約了帶寬資源。
支持服務器主動推送資源
HTTP/3
基于UDP實現了一個可靠的傳輸協議QUIC,解決了TCP隊頭阻塞問題
HTTP/2 多個請求是跑在一個 TCP 連接中的,那么當 TCP 丟包時,整個 TCP 都要等待重傳,那么就會阻塞該 TCP 連接中的所有請求。
TCP與TLS的握手時延遲
發起 HTTP 請求時,需要經過 TCP 三次握手和 TLS 四次握手(TLS 1.2)的過程,因此共需要 3 個 RTT 的時延才能發出請求數據。
網絡遷移需要重新連接
一個 TCP 連接是由四元組(源 IP 地址,源端口,目標 IP 地址,目標端口)確定的,這意味著如果 IP 地址或者端口變動了,就會導致需要 TCP 與 TLS 重新握手,這不利于移動設備切換網絡的場景,比如 4G 網絡環境切換成 WiFi。
這些問題都是 TCP 協議固有的問題,無論應用層的 HTTP/2 在怎么設計都無法逃脫。要解決這個問題,就必須把傳輸層協議替換成 UDP,這個大膽的決定,HTTP/3 做了!
QUIC協議的提出!!!
用UDP代替TCP,我們都知道UDP是一個簡單不可靠的傳輸協議,UDP包之間不需要有序,而且不需要建立連接,即沒有握手揮手,那自然是快的。
但是在傳輸數據前雖然需要 QUIC 協議握手,這個握手過程只需要 1 RTT,握手的目的是為確認雙方的「連接 ID」,連接遷移就是基于連接 ID 實現的(而非源 IP 地址,源端口,目標 IP 地址,目標端口四元組)。
當然,HTTP/3 不僅僅只是簡單將傳輸協議替換成了 UDP,還基于 UDP 協議在「應用層」實現了 QUIC 協議,它具有類似 TCP 的連接管理、擁塞窗口、流量控制的網絡特性,相當于將不可靠傳輸的 UDP 協議變成“可靠”的了,所以不用擔心數據包丟失的問題。
每個數據包都有一個序號唯一標識。當某個流中的一個數據包丟失了,即使該流的其他數據包到達了,數據也無法被 HTTP/3 讀取,直到 QUIC 重傳丟失的報文,數據才會交給 HTTP/3。
而其他流的數據報文只要被完整接收,HTTP/3 就可以讀取到數據。這與 HTTP/2 不同,HTTP/2 只要某個流中的數據包丟失了,其他流也會因此受影響。
QUIC 協議并不是與 TLS 分層,而是 QUIC 內部包含了 TLS,它在自己的幀會攜帶 TLS 里的“記錄”,再加上 QUIC 使用的是 TLS 1.3,因此僅需 1 個 RTT 就可以「同時」完成建立連接與密鑰協商,甚至在第二次連接的時候,應用數據包可以和 QUIC 握手信息(連接信息 + TLS 信息)一起發送,達到 0-RTT 的效果。