简介

HTTP/2(RFC 7540,2015 年发布)是自 1999 年 HTTP/1.1 以来的第一次重大升级,目标是在不改变应用语义的前提下,改善延迟、并发和网络效率。浏览器端基本只在 TLS 上启用(h2),明文 h2c 仅用于内部服务间通信。

  • h2:HTTP/2 over TLS(最常见,浏览器只支持这一种)
  • h2c:HTTP/2 over TCP(无加密)

设计背景

移动端和富媒体时代请求量激增,HTTP/1.1 的队头阻塞、多个 TCP 连接并行带来的慢启动 / 拥塞竞争成为瓶颈。

谷歌的 SPDY 原型验证了「单连接、多路复用、压缩头部」的思路;IETF 在 SPDY 3.1 基础上标准化为 HTTP/2。

核心特性

特性作用
二进制分帧(Binary Framing)把 HTTP 报文拆成小型 Frame,机器易解析、可并行
多路复用(Multiplexing)多个请求 / 响应共享一个 TCP 连接,互不阻塞
流与优先级(Stream & Priority)每个请求是双向 Stream,可指定权重与依赖
头部压缩(HPACK)静态 Huffman + 动态表,大幅减少重复 Header 字节
服务器推送(Server Push)Chrome 106(2022-09)已移除,由 103 Early Hints 取代
流量控制端到端窗口,避免单个大文件占满带宽

多路复用解决的是应用层队头阻塞 —— TCP 层的队头阻塞依然存在(任意一个包丢失,连接上所有 stream 全停),这正是 HTTP/3 改走 QUIC over UDP 要解决的问题。

NGINX 配置

启用 HTTP/2 需要 HTTPS,本地证书参考 在本地环境使用 HTTPS | ZYF.IM

# /etc/nginx/conf.d/default.conf
server {
    listen 443 ssl;
    http2 on;                                # NGINX 1.25.1+ 的新语法

    server_name localhost;
    ssl_certificate     /etc/ssl/certs/localhost.pem;
    ssl_certificate_key /etc/ssl/certs/localhost-key.pem;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;            # demo 用,生产请见下文
    ssl_prefer_server_ciphers on;

    location / {
        root  /usr/share/nginx/html;
        index index.html index.htm;
    }
}
docker container restart nginx-ssl

几个常被问到的细节

  • http2 on; 的版本要求。NGINX 1.25.1(2023-05)才引入独立的 http2 指令,更早的版本要写 listen 443 ssl http2;。老语法仍可用,但已被官方建议替换。
  • ALPN 协商。HTTP/2 over TLS 必须靠 ALPN 在 TLS 握手时协商出 h2。OpenSSL 1.0.2+ 默认支持,NGINX 启用 TLS 即自动具备,不需要额外指令
  • cipher 列表别复制 demoHIGH:!aNULL:!MD5 是 NGINX 默认列表,还包含一些过时套件。生产环境请用 Mozilla SSL Configuration Generator 生成 intermediate 或 modern 配置,自动剔除 RC4、3DES、CBC mode 等弱套件。
  • Server Push 已死,用 103 Early Hints。Chrome 106 正式移除 push 支持。替代方案是服务器在主响应前发一个 103 Early Hints 响应,携带 Link: </app.css>; rel=preload,浏览器立即开始拉取。NGINX 1.13.9+ 通过 ngx_http_v2_modulehttp2_push_preload 已不推荐,HTTP 层的 Early Hints 需要应用配合。
  • HPACK → QPACK。HTTP/2 的 HPACK 因动态表有顺序依赖,会被 TCP 队头阻塞拖累;HTTP/3 改用 QPACK 解耦编解码顺序。这是 HTTP/3 性能优势的关键设计之一。

测试

浏览器

访问 https://localhost:8443/,Chrome DevTools Network 面板勾选 Protocol 列,看到 h2 即生效。

或装 HTTP Indicator 扩展:HTTP/1.1 灰、HTTP/2 蓝、HTTP/3 绿。

curl

# -I (--head) 只返回响应头
curl -I https://localhost:8443/

HTTP/2 200
server: nginx/1.29.0
date: Fri, 27 Jun 2025 01:56:55 GMT
content-type: text/html
content-length: 615

nghttp / h2load

nghttp2 工具包提供更底层的视图,能打出 ALPN 协商结果、HPACK 表、stream 详情:

brew install nghttp2

nghttp -nv https://localhost:8443/    # 单请求 + 详细协议输出
h2load -n 1000 -c 10 https://localhost:8443/   # 1000 请求 / 10 连接的压测

h2load 还能直接对比 h1 / h2 / h3 的吞吐 (--h1--alpn-list=h3,h2),调参时比 ab 更贴近真实场景。

HTTP/3

继续看 NGINX 启用 HTTP/3 | ZYF.IM

References

– EOF –