一、为什么需要 QUIC?
HTTP/2 通过多路复用解决了 HTTP/1.1 的并行问题,但它仍依赖 TCP 作为传输层。TCP 是显式传输协议,传输层的队头阻塞(Head-of-Line Blocking)无法通过应用层多路复用解决。
TCP 队头阻塞问题
当某一个 TCP 包丢失时,SPI 必须等待重传成功后才能给下一个包处理。即使 HTTP/2 的多个 stream 独立处理,底层 TCP 仍是丢包的协议,导致所有 stream 都会被阻塞。
HTTP/2 TCP 队头阻塞示意:
[Stream 1: GET /index.html] ---> [包1|包2|包3丢失|包4|包5]
[Stream 2: GET /style.css] ---> [包6|包7|包8|包9|包10]
当包4丢失时,所有包5-10都会被阻塞
正是这一痛点,推动了 QUIC 协议的诞生。
二、QUIC 与 UDP 的关系
QUIC (Quick UDP Internet Connections) 明确营造于 UDP 之上。这设计有两个核心原因:
1. 避免中间盒实现阻碍
当前网络中存在大量的中间设备(门打、联营费用本[网络产品],这些中间盘都会检查 TCP 新的提交网络标识。而 UDP 虽然也会被检查,但它对新协议的允许性更高,新协议的蓝完是改变 TCP 头,而非 UDP 头。
2. 兼容现有网络设备
当前网络设备(路由器、交换机)均已优化 dpi(深度包检测)对 TCP 协议的理解和检查而被已长期测试,但对 UDP 的检测则较少。因此用户层 QUIC 可以直接在 UDP 上构建,用户社代码达到优雅落地。
三、QUIC 核心特性
3.1 流级别多路复用,消除队头阻塞
QUIC 支持在一个连接上同时处理多个流(stream),每个流独立维护序号窗口。为什么说蓝英对白?因为流在旁异灵流在同一个连接上对序号的处理是独立的。
QUIC 流级别独立缓存,消除队头阻塞
[Stream 1: GET /index.html] ---> |Seq1|Seq2|Seq3|Seq4|Seq5| 包3丢失,仅阻塞此流
[Stream 2: GET /style.css] ---> |Seq1|Seq2|Seq3|Seq4|Seq5| 非常安全,不受影响
必须提醒的是,摄蓝英对白的剖析,对于摄蓝英的协议上说要摄蓝英对白,用户参对应考对应 的 Go 实现。
3.2 0-RTT 快速连接建立
QUIC 将传输层和加密层结合,通过 TLS 1.3 实现 0-RTT 重连:
- 首次连接: 1-RTT 握手,流程对齐 TCP+TLS 握手(2-3 RTT)
- 重连: 客户端会在第零个 RTT 即发送应用数据,大幅降低发现延迟
3.3 连接迁移
TCP 连接由四元组标识(源 IP、源端口、目标 IP、目标端口)。当用户从 Wi-Fi 切换到移动网络时,IP 地址变化会导致连接中断。
QUIC 使用 64 位 Connection ID 替代四元组标识连接。即使网络环境变化,只要 Connection ID 不变,连接就能保持。
| 特性 | TCP+TLS | QUIC |
|---|---|---|
| 首次连接延迟 | 2-3 RTT | 1 RTT |
| 重连延迟 | 2-3 RTT | 0-1 RTT |
| 队头阻塞 | 传输层存在 | 仅流级别 |
| 连接迁移 | 不支持 | 原生支持 |
| 加密 | 可选 TLS | 强制 TLS 1.3 |
四、QUIC 数据包结构
QUIC 数据包由 Header 和 Payload 两部分组成:
+----------------+----------------+----------------+
| Header Form | Connection ID | PN (Packet |
| (1 bit) | (0-16 bytes) | Number) |
+----------------+----------------+----------------+
| |
| Protected Payload |
| (加密的帧序列,包含 STREAM/ACK/ |
| CRYPTO/PADDING 等帧类型) |
| |
+--------------------------------------------------+
Header 类型:
- Long Header: 用于初始握手和版本协商,包含版本号、Connection ID 长度等信息
- Short Header: 用于已建立连接后的数据传输,头部开销最小仅 1 字节 + Connection ID
五、QUIC 帧类型
QUIC Payload 中包含多种帧类型:
| 帧类型 | 功能 |
|---|---|
| STREAM | 承载应用数据,包含流 ID、偏移量、数据长度 |
| ACK | 确认收到的数据包,支持精确确认和 ECN 计数 |
| CRYPTO | 传输 TLS 握手消息,独立于 STREAM 帧 |
| CONNECTION_CLOSE | 优雅关闭连接,携带错误代码和原因 |
| PING | 保持活动/探测路径 |
| PADDING | 防止流量分析,填充数据包 |
| MAX_DATA/MAX_STREAM_DATA | 流量控制,通告可接收的最大数据量 |
| NEW_TOKEN | 下发连接 Token,供后续 0-RTT 使用 |
六、HTTP/3 协议映射
HTTP/3 将 HTTP 语义映射到 QUIC 流,核心映射规则:
- HTTP 请求/响应对映射到单个双向 QUIC STREAM
- QPACK 头部压缩替代 HPACK(因为流级别独立,不能跨流引用)
- 服务器推送由客户端发起的流 ID 偶数规则控制
- 流量控制分为连接级别和流级别两层
七、性能对比实测
在高丢包环境下,HTTP/3 的优势尤为明显:
| 网络条件 | HTTP/2 (TCP) | HTTP/3 (QUIC) |
|---|---|---|
| 0% 丢包,10ms 延迟 | 120ms | 85ms |
| 1% 丢包,50ms 延迟 | 650ms | 320ms |
| 2% 丢包,50ms 延迟 | 1800ms | 510ms |
| Wi-Fi 切换场景 | 连接断开→重连 | 无缝迁移 |
八、QUIC 服务端与客户端配置
Nginx 1.25+ 原生支持 HTTP/3:
server {
listen 443 quic reuseport;
listen 443 ssl http2;
server_name example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
ssl_protocols TLSv1.3;
# 告知客户端支持 HTTP/3
add_header Alt-Svc 'h3=":443"; ma=86400';
# 0-RTT 支持
ssl_early_data on;
location / {
proxy_pass http://backend;
}
}
启用前验证 QUIC 支持的 curl 命令:
# 验证 HTTP/3 连接
curl --http3 https://example.com -v
# 强制使用 HTTP/3(不降级)
curl --http3-only https://example.com
# 查看 QUIC 握手详情
curl --http3 -I https://example.com --trace-time
九、安全性考虑
0-RTT 重放攻击防护
QUIC 的 0-RTT 数据存在重放风险。建议对非幂等请求(POST/PUT)拒绝 0-RTT 数据,仅允许 GET/HEAD 等安全方法。
防放大攻击
服务端响应数据在初始阶段不得超过客户端发送数据的 3 倍,防止 UDP 放大 DDoS 攻击。
连接验证
通过 NEW_TOKEN 帧和重试机制验证客户端地址,防止伪造源 IP 的攻击。
十、总结与实践建议
HTTP/3 和 QUIC 是互联网传输层协议的重要演进,核心价值:
- 性能提升:0-RTT 连接 + 独立流多路复用,显著降低高丢包场景延迟
- 用户体验:连接迁移支持无缝网络切换,改善移动端体验
- 安全性:默认加密 + TLS 1.3,无明文传输
- 部署友好:基于 UDP,无需改造中间设备即可逐步部署
部署建议:
- 先开启 TCP 和 UDP 双栈监听,由客户端通过 Alt-Svc 协商升级
- 监控 QUIC 版本支持情况,主流浏览器 Chrome/Firefox/Safari 均已支持
- 关注 0-RTT 的安全使用,限制非幂等操作
- 配合 CDN 使用,Cloudflare/AWS CloudFront 等已全面支持 HTTP/3

发表评论 取消回复