文章

HTTP/3与QUIC协议深度解析

一句话搞懂 HTTP/3 为什么换掉 TCP,0-RTT、连接迁移、无队头阻塞到底怎么做到的。

HTTP/3与QUIC协议深度解析

一句话概括

HTTP/3 是 HTTP 协议的最新版本,底层弃用 TCP、改用基于 UDP 的 QUIC 协议。它在传输层内置了 TLS 1.3 加密,实现了 0-RTT 快速重连、网络切换不掉线的连接迁移,以及彻底消除 HTTP/2 的队头阻塞问题。2022 年成为 RFC 9114 标准,如今全球超 80% 浏览器流量已走 HTTP/3。

核心知识点

1. 为什么弃用 TCP?

TCP 运行在操作系统内核里,升级一个 TCP 特性(比如 TCP Fast Open)要等全球数十亿设备的内核更新,周期 5-10 年。QUIC 跑在用户态(Chrome/nginx/CDN 代码里),发个浏览器版本就能迭代。Cloudflare 曾在 3 天内用 QUIC 修了一个全局拥塞控制 bug——换 TCP 根本做不到。

另外 TCP + TLS 是两层独立协议,握手要 2 RTT;QUIC 把 TLS 1.3 融合进传输层,初次 1 RTT,重连 0 RTT。

1
2
3
4
5
// TCP: 连接 = 四元组绑定,IP 一变就断
// {src_ip, src_port, dst_ip, dst_port} → 任何一个变了,连接死

// QUIC: 连接 = Connection ID 标识,IP 随便换
// Server 给 Client 发一个 8-20 字节随机 CID,用 CID 认连接

2. 0-RTT 是怎么做到的?

客户端首次连接后缓存服务器的 PSK(Pre-Shared Key)和传输参数。重连时用缓存的密钥直接加密 HTTP 请求,跟握手包同时发出——服务器收到就能解密,省掉一整轮往返。

1
2
3
4
5
6
7
8
9
首次连接(1-RTT):
Client → Server:  Initial (ClientHello)
Server → Client:  Initial (ServerHello) + Handshake (证书+参数)
Client → Server:  Handshake (Finished) + HTTP 请求  ← 1 RTT 后发数据

重连(0-RTT):
Client → Server:  0-RTT (HTTP 请求直接加密发出!) + Initial
Server → Client:  Initial + HTTP 响应
// 请求和数据第一轮一起走了,0 RTT

⚠️ 0-RTT 有重放攻击风险——攻击者截获请求可以重复发送。所以只对 GET/HEAD 等幂等请求开启 0-RTT,POST/PUT 一般禁用。

3. 队头阻塞:HTTP/2 vs HTTP/3

HTTP/2 的死穴:虽然支持多路复用(一个 TCP 连接上跑多个流),但 TCP 要求字节流按序交付。流 1 丢了一个包,TCP 必须等重传成功才把后续所有流的数据交给应用层——流 2、流 3 的数据明明到了却卡在缓冲区。

1
2
HTTP/2: 流1丢包 → 所有流都卡住
HTTP/3: 流1丢包 → 只有流1等重传,流2、流3正常交付

QUIC 给每个流独立的序列号空间,丢包只管自己的流。5% 丢包的蜂窝网络上,HTTP/2 吞吐量能跌 50%,HTTP/3 只跌 5-10%。

1
2
3
4
5
6
7
8
9
10
11
12
13
// 概念演示:QUIC 多流独立传输
const streams = new Map(); // streamId → { buffer: Map, nextOffset: 0 }

function onPacket(streamId, offset, data) {
  const s = streams.get(streamId) || { buffer: new Map(), nextOffset: 0 };
  s.buffer.set(offset, data);
  // 只关心本流连续性,其他流的丢包不阻塞这里
  while (s.buffer.has(s.nextOffset)) {
    deliverToApp(s.buffer.get(s.nextOffset));
    s.nextOffset += s.buffer.get(s.nextOffset).length;
  }
  streams.set(streamId, s);
}

4. 连接迁移:Wi-Fi 切 5G 不掉线

TCP 用四元组识别连接,切换网络 = IP 变了 = 连接断开,需要重建三次握手 + TLS,1-3 秒不可用。QUIC 用 Connection ID 认连接,客户端换了 IP 后发新包带上不变 CID,服务端认出是同一个会话,无缝恢复。YouTube 部署 QUIC 后网络切换中断时间从 1200ms 降到 80ms。

5. QPACK:为 QUIC 设计的头部压缩

HTTP/2 的 HPACK 依赖所有流共享有序压缩上下文——QUIC 的流独立传递会打乱顺序,HPACK 直接没法用。QPACK 把表更新指令放到独立的”编码器流”里,请求流只带一个 Required Insert Count 字段告诉解码器”先处理到表状态的哪个版本再解压”,这样就支持乱序了。

其实你每天都在用

  • 看 YouTube / Bilibili 视频:Google 的 QUIC 部署让视频起播更快,拖动进度条的响应延迟明显降低
  • 用 ChatGPT / Claude:这些 AI 产品的 SSE 流式响应,底层大概率走 QUIC。丢一个 token 只重传那一个,不影响后续 token 的到达
  • 微信视频通话:跨网络切换(Wi-Fi→5G)时你不会感觉到卡顿——QUIC 连接迁移在底层默默恢复
  • 淘宝/京东的瀑布流:大量图片和接口并行加载,HTTP/3 多路复用比 HTTP/2 在高丢包 4G/5G 网络下快 30-50%
  • Chrome DevTools Network 面板:看到 h3 协议标记的那些请求,就是走的 HTTP/3

常见误解(FAQ)

❌ 误区一:”QUIC 就是 UDP 加层皮,不稳定”

UDP 本身不保证可靠,但 QUIC 在 UDP 之上实现了一套完整的可靠传输机制——包确认(ACK)、丢包检测(RACK 算法)、重传、拥塞控制(BBR)——可靠性完全不输 TCP,而且因为丢包重传不阻塞其他流,实际体验往往更好。

❌ 误区二:”HTTP/3 就是 HTTP/2 换了传输层,其他一样”

不只是换传输层。HTTP/3 重新设计了头部压缩(QPACK 替代 HPACK)、帧结构、流优先级机制,连 SETTINGS 帧的语义都不同。它是针对 QUIC 特性从头设计的,不是简单的移植。

❌ 误区三:”0-RTT 可以随便用,反正更快”

0-RTT 有重放攻击风险——攻击者可以截获 0-RTT 请求包反复发给服务器。生产环境中通常只对 GET/HEAD 等幂等请求开启 0-RTT,修改类操作走完整握手。服务器侧还需实现重放窗口检测。

❌ 误区四:”UDP 容易被防火墙拦截,HTTP/3 用不了”

这是 QUIC 推广早期的主要障碍,部分企业防火墙确实会丢 UDP 包。但 Google、Cloudflare、Akamai 的广泛部署已经在推动网络环境改善。而且 QUIC 有自动降级机制——如果 UDP 不通,客户端会回退到 HTTP/2 over TCP,对用户透明。

一句话总结

HTTP/3 不只是”换了个传输层”,而是把互联网传输从”内核态的黑盒”变成了”应用态的可编程基础设施”——从此拥塞控制、丢包恢复、连接管理都能通过软件更新快速迭代,TCP 四十年的演进瓶颈被打通了。

本文由作者按照 CC BY 4.0 进行授权