简介
HTTP/2 解决了“多路复用、头部压缩、优先级”等 HTTP/1.x 的瓶颈,但仍受 TCP 先天限制。
HTTP/3 则把同样的语义搬到 QUIC,Quick UDP Internet Connections 是 Google 设计的一种基于 UDP 的多路复用安全传输层协议。标准化后,HTTP/3 = HTTP over QUIC。
层级 | HTTP/2 | HTTP/3 |
---|---|---|
传输 | TCP (必)+ TLS1.2/1.3(多数场景) | QUIC (UDP 之上)+ TLS1.3(强制) |
流(Stream) | Mux 在 TCP 里的逻辑流 | Mux 在 QUIC 原生流 |
头压缩 | HPACK | QPACK(避免队头阻塞) |
- HTTP/2 浏览器要求必须跑在 TLS 之上(ALPN=“h2”)。栈变为 HTTP/2 → TLS → TCP → IP。
- HTTP/3 使用 QUIC 替换 TCP,栈变为 HTTP/3 → QUIC (拥塞/重传) → UDP → IP,加密集成在 QUIC(基于 TLS 1.3)。
Mux
multiplex 多路复用- HTTP/2 必须顺序传输,而 HTTP/3 支持乱序
- 如果沿用 HPACK,丢一个 UDP 包就会让所有流的头部解码卡住,因此 IETF 为 HTTP/3 设计了 QPACK 来“避开队头阻塞 (Head-of-Line Blocking, HoL)”。
- 连接迁移。通过 Connection ID 识别会话,IP 或端口改变(如移动网络/Wi-Fi 切换)无需重新建立连接。
使用 HTTP3 的网站:
开始实验
启用 HTTP/3 需要使用 HTTPS,请先参考 在本地环境使用 HTTPS | ZYF.IM。
修改 NGINX default.conf 配置文件,启用 HTTP/3:
# vi default.conf
server {
# for better compatibility it's recommended
# to use the same port for http/3 and https
# 浏览器首次只能走 TCP,因此必须提供一个 HTTPS 入口,再通过 `Alt-Svc` 升级到 HTTP/3
listen 443 ssl;
# Quick UDP Internet Connections
# quic 关键字表示使用 UDP 监听,承载 QUIC/HTTP-3
# reuseport 关键字表示复用端口,允许多个 NGINX 实例共享同一端口
listen 443 quic reuseport;
http2 on;
# 启用 HTTP/3,默认是 on
http3 on;
server_name localhost;
ssl_certificate /etc/ssl/certs/localhost.pem;
ssl_certificate_key /etc/ssl/certs/localhost-key.pem;
# 启用 TLS 允许 0-RTT(Early Data),允许客户端在 TLS 1.3 的重连阶段携带早期数据
# 对 HTTP/3 非必需,但 QUIC 天生支持 0-RTT;此处保持一致
ssl_early_data on;
# 仅启用 TLSv1.3
ssl_protocols TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# 添加 Alt-Svc 头,向客户端声明可升级到 HTTP/3
# Alt-Svc 头告诉浏览器“该资源在同一主机的 UDP/443 上能用 h3 协议”,浏览器会自动重试
# ma max-age 缓存时间,86400 秒 = 1 天
# always 关键字保证即使发生 4xx/5xx 也发送 Alt-Svc,便于调试
add_header alt-svc 'h3=":443"; ma=86400' always;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}
# docker rm -f nginx-ssl
# 添加监听 UDP 端口
docker run -d --name nginx-ssl \
-p 443:443 \
-p 443:443/udp \
-v ./default.conf:/etc/nginx/conf.d/default.conf:ro \
-v ./localhost.pem:/etc/ssl/certs/localhost.pem:ro \
-v ./localhost-key.pem:/etc/ssl/certs/localhost-key.pem:ro \
-v ./html/:/usr/share/nginx/html/:ro \
nginx:alpine
# docker container restart nginx-ssl
测试
curl
# 使用支持 HTTP/3 的 curl
# docker run -ti --rm alpine/curl-http3 curl -V
docker run -ti --network host --rm alpine/curl-http3 curl -I --http3 https://localhost/
HTTP/3 200
server: nginx/1.29.0
date: Fri, 27 Jun 2025 03:26:09 GMT
content-type: text/html
content-length: 656
last-modified: Fri, 27 Jun 2025 03:17:07 GMT
etag: "685e0d33-290"
alt-svc: h3=":443"; ma=86400
accept-ranges: bytes
游览器
无法验证成功!分析原因:
- 之前 UDP 使用的是 8443,当将相关配置都改为 433 仍然在 Chrome Network 里无法看见 h3。
- 可能 Chrome 对 localhost 或者域名解析到 127.0.0.1 的访问 block HTTP3。
为了验证第 2 种情况,通过 AWS EC2 + 自己的域名 + Let’s Encrypt 颁发的证书后,再仿照 HTTP3 在本地配置的方法。最终在 Chrome 中成功验证 HTTP3。
使用 Chrome 插件 HTTP Indicator:
- HTTP/1.1 显示为灰色。
- HTTP/2 显示为蓝色。
- HTTP/3 显示为绿色。
如何配置 AWS EC2 + 自己的域名 + Let’s Encrypt 颁发的证书,参考:
References
– EOF –