HTTP/3 与 QUIC 协议
1. 为什么需要 QUIC?
HTTP/2 over TCP 的问题
- TCP 队头阻塞: 一个包丢失,所有 Stream 阻塞等待重传
- 握手延迟: TCP 3-RTT + TLS 1-2 RTT = 连接建立慢
- 连接迁移困难: IP 变化 (WIFI → 4G) 需重新握手
QUIC 的解决方案
- 基于 UDP: 用户空间实现可靠传输,绕过内核 TCP 栈
- Stream 独立: 一个 Stream 丢包不影响其他 Stream
- 0-RTT / 1-RTT 握手: 内置 TLS 1.3
- Connection ID: 连接与 IP 解耦
2. QUIC 核心特性
2.1 多路复用无队头阻塞
HTTP/2 over TCP:
Stream 1 ─┬─ Packet Lost ─┬─> ALL BLOCKED
Stream 2 ─┘ │
Stream 3 ─────────────────┘
QUIC:
Stream 1 ─── Packet Lost ──> Only Stream 1 blocked
Stream 2 ─────────────────> OK
Stream 3 ─────────────────> OK2.2 0-RTT 握手
传统 TCP + TLS:
Client Server
|------- SYN ------->| (1 RTT)
|<----- SYN+ACK -----|
|------- ACK ------->|
|--- ClientHello --->| (2 RTT)
|<-- ServerHello ----|
|---- Finished ----->| (3 RTT)
|<---- Data ---------|
QUIC 0-RTT (恢复连接):
Client Server
|-- ClientHello + Data -->| (0 RTT for data!)
|<-- ServerHello + Data --|实现原理: 客户端缓存 Session Ticket,下次连接直接发送加密数据。
2.3 Connection ID
- 连接由 Connection ID 标识,而非 (IP, Port) 四元组
- 网络切换 (WIFI → 4G) 时,Connection ID 不变,连接不中断
- 对移动端 App 极为重要
2.4 拥塞控制
- 默认使用 Cubic (与 TCP 类似)
- 支持 BBR (Google 开发,基于带宽估计)
- 可插拔设计,易于升级
3. HTTP/3 协议栈
+---------------------+
| HTTP/3 | (语义与 HTTP/2 相同)
+---------------------+
| QPACK | (类似 HPACK,但无序)
+---------------------+
| QUIC | (传输层,含加密)
+---------------------+
| UDP |
+---------------------+
| IP |
+---------------------+QPACK vs HPACK
- HPACK 依赖有序传输 (动态表需同步)
- QPACK 允许乱序,适应 QUIC 的无序 Stream
4. 前端如何感知 HTTP/3?
检测协议版本
javascript
// Performance API
const entries = performance.getEntriesByType('navigation');
console.log(entries[0].nextHopProtocol); // "h3" / "h2" / "http/1.1"
// 或资源
const resources = performance.getEntriesByType('resource');
resources.forEach(r => console.log(r.name, r.nextHopProtocol));Alt-Svc 升级机制
服务端通过 Alt-Svc 响应头告知客户端支持 HTTP/3:
http
Alt-Svc: h3=":443"; ma=86400浏览器后续请求自动尝试 QUIC。
5. 部署现状 (2024)
- Cloudflare, Google, Meta 已全面支持
- Nginx 1.25+ 支持 (需编译 quiche/boringssl)
- Node.js 实验性支持 (
--experimental-quic)