HTTP/3 與 QUIC 協定:基於 UDP 的革命
HTTP/3 是 HTTP 協定的最新版本,它做出了一個大膽的決定:拋棄 TCP,改用 QUIC。這是網路協定史上罕見的革命性變革。
一、 為什麼需要 HTTP/3?
1.1 HTTP/2 的遺留問題
HTTP/2 雖然解決了應用層的隊頭阻塞,但仍有問題:
一個 TCP 封包丟失,整個連線的所有串流都要等待重傳。
1.2 TCP 的先天限制
| 問題 | 說明 |
|---|---|
| 隊頭阻塞 | 一個封包丟失阻塞所有資料 |
| 握手延遲 | TCP + TLS 需要 2-3 RTT |
| 連線遷移 | 換 IP 需要重新握手 |
| 協定僵化 | 中間設備阻礙 TCP 改進 |
1.3 解決方案:QUIC
QUIC(Quick UDP Internet Connections)是 Google 設計的新傳輸協定:
二、 QUIC 核心特性
2.1 基於 UDP
QUIC 建立在 UDP 之上:
| 面向 | TCP | QUIC |
|---|---|---|
| 可靠性 | 內建 | QUIC 自己實作 |
| 順序 | 保證 | 每個串流獨立 |
| 擁塞控制 | 內建 | QUIC 自己實作 |
| 加密 | TLS 疊加 | 內建 TLS 1.3 |
2.2 獨立串流
HTTP/2 的問題:
所有串流都被阻塞。
QUIC 的解決:
只有受影響的串流被阻塞,其他繼續傳輸。
2.3 0-RTT 連線建立
TCP + TLS 的延遲:
總延遲:2-3 RTT
QUIC 的優化:
首次連線:1 RTT重新連線:0 RTT(使用之前的金鑰)
2.4 連線遷移
傳統 TCP 用 IP:Port 識別連線:
連線 ID = 192.168.1.1:12345 → 1.2.3.4:443換 WiFi 或切換到行動網路 → IP 變了 → 連線斷開 → 需要重新握手
QUIC 用 Connection ID:
連線 ID = 0x1234567890abcdefIP 變了沒關係,Connection ID 不變就不斷線!
2.5 內建加密
QUIC 強制使用 TLS 1.3:
- 沒有不加密的 QUIC
- 連標頭都加密(保護隱私)
- 中間設備無法篡改
QUIC 封包結構:
┌─────────────────────────────────────┐
│ 短標頭 / 長標頭 │
├─────────────────────────────────────┤
│ 加密的 Payload │
│ (Frames, 包括 HTTP/3 資料) │
└─────────────────────────────────────┘三、 HTTP/3 特性
3.1 QPACK 標頭壓縮
HTTP/2 的 HPACK 依賴順序傳輸,不適合 QUIC。
HTTP/3 用 QPACK,解決亂序問題:
| 面向 | HPACK | QPACK |
|---|---|---|
| 動態表更新 | 內嵌在標頭中 | 獨立的串流 |
| 順序依賴 | 必須按序 | 可亂序 |
3.2 優先級簡化
HTTP/2 的依賴樹太複雜。HTTP/3 用 Priority Hints:
http
:path: /style.css
priority: u=0, i
# u= urgency (0-7, 0 最高)
# i= incremental (可增量傳輸)3.3 無 Server Push
HTTP/3 規範中保留了 Server Push,但由於 HTTP/2 的經驗:
NOTE
實務上很少使用,大多數實作都停用。
四、 QUIC 封包結構
4.1 長標頭(連線建立時)
Long Header:
┌─────────────────────────────────────┐
│ Header Form (1) = 1 │
│ Fixed Bit (1) = 1 │
│ Long Packet Type (2) │
│ Reserved (2) │
│ Packet Number Length (2) │
├─────────────────────────────────────┤
│ Version (32) │
├─────────────────────────────────────┤
│ DCID Length (8) + DCID (0-160) │
├─────────────────────────────────────┤
│ SCID Length (8) + SCID (0-160) │
├─────────────────────────────────────┤
│ Payload │
└─────────────────────────────────────┘4.2 短標頭(連線建立後)
Short Header:
┌─────────────────────────────────────┐
│ Header Form (1) = 0 │
│ Fixed Bit (1) = 1 │
│ Spin Bit (1) │
│ Reserved (2) │
│ Key Phase (1) │
│ Packet Number Length (2) │
├─────────────────────────────────────┤
│ Destination Connection ID (0-160) │
├─────────────────────────────────────┤
│ Packet Number (8-32) │
├─────────────────────────────────────┤
│ Payload (加密) │
└─────────────────────────────────────┘4.3 QUIC Frames
QUIC 封包包含多個 Frame:
| Frame 類型 | 用途 |
|---|---|
| STREAM | 傳輸資料 |
| ACK | 確認收到 |
| CRYPTO | TLS 握手 |
| PADDING | 填充 |
| PING | 保活 |
| RESET_STREAM | 終止串流 |
| CONNECTION_CLOSE | 關閉連線 |
五、 效能比較
5.1 握手延遲
| 場景 | TCP+TLS | QUIC |
|---|---|---|
| 首次連線 | 2-3 RTT | 1 RTT |
| 重新連線 | 1-2 RTT | 0 RTT |
5.2 丟包恢復
5.3 網路切換
| 場景 | TCP | QUIC |
|---|---|---|
| WiFi → 4G | 斷線重連 | 無縫切換 |
| 延遲 | 2-3 RTT | 0 |
六、 部署現狀
6.1 瀏覽器支援
| 瀏覽器 | HTTP/3 支援 |
|---|---|
| Chrome | ✅ 87+ |
| Firefox | ✅ 88+ |
| Safari | ✅ 14+ |
| Edge | ✅ 87+ |
6.2 伺服器支援
| 伺服器/服務 | 支援 |
|---|---|
| Cloudflare | ✅ |
| Google Cloud | ✅ |
| AWS CloudFront | ✅ |
| Nginx | ⚠️ 實驗性 |
| Caddy | ✅ |
6.3 檢查網站是否支援
bash
# 使用 curl
curl -I --http3 https://cloudflare.com
# 使用 Chrome DevTools
# Network 面板 → Protocol 欄位顯示 h3七、 潛在問題
7.1 UDP 封鎖
某些網路環境封鎖 UDP:
解決:HTTP/3 自動回退到 HTTP/2。
7.2 0-RTT 重放攻擊
0-RTT 資料可能被重放:
對策:
- 0-RTT 只用於冪等請求
- 伺服器實作重放保護
7.3 CPU 使用
QUIC 在應用層實作:
- 沒有核心態優化
- CPU 使用較高
- 正在積極優化中
總結
| 特性 | HTTP/2 | HTTP/3 |
|---|---|---|
| 傳輸協定 | TCP | QUIC (UDP) |
| 隊頭阻塞 | TCP 層存在 | 完全解決 |
| 握手延遲 | 2-3 RTT | 1 RTT / 0 RTT |
| 連線遷移 | 不支援 | 支援 |
| 加密 | TLS 疊加 | 內建強制 |
| 標頭壓縮 | HPACK | QPACK |
> **核心要點**:HTTP/3 + QUIC 是網路協定的未來。它解決了 TCP 的根本限制,帶來更快、更可靠、更適合行動網路的體驗。
進階挑戰
- 使用 Chrome DevTools 找出哪些你常用的網站已經支援 HTTP/3。
- 研究 QUIC 的擁塞控制演算法(如 BBR)與 TCP 的差異。
- 思考:為什麼 QUIC 選擇在 UDP 之上重新實作可靠性,而不是修改 TCP?