简介

HTTP/2 解决了“多路复用、头部压缩、优先级”等 HTTP/1.x 的瓶颈,但仍受 TCP 先天限制。

HTTP/3 则把同样的语义搬到 QUIC,Quick UDP Internet Connections 是 Google 设计的一种基于 UDP 的多路复用安全传输层协议。标准化后,HTTP/3 = HTTP over QUIC。

层级HTTP/2HTTP/3
传输TCP (必)+ TLS1.2/1.3(多数场景)QUIC (UDP 之上)+ TLS1.3(强制)
流(Stream)Mux 在 TCP 里的逻辑流Mux 在 QUIC 原生流
头压缩HPACKQPACK(避免队头阻塞)
  • 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

游览器

无法验证成功!分析原因:

  1. 之前 UDP 使用的是 8443,当将相关配置都改为 433 仍然在 Chrome Network 里无法看见 h3。
  2. 可能 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 –