HTTP/2 总览

h2 改了什么、没改什么,以及 ALPN 协商与 h2c 的废弃。

作者 David更新于 第 1 篇(共 16 篇)

改了什么

HTTP/2 只替换 RFC 9112 那一层——报文成帧与连接管理。对照 1.1 的报文结构:

1.1 的机制h2 的替代
文本 start-line + 字段行 + CRLF二进制帧(9 字节定长头)
Content-Length / chunked 定界帧头的 Length 字段 + END_STREAM 标志
一连接一请求(或串行流水线)流(stream)多路复用
明文重复的字段HPACK 压缩 + 跨请求的动态表
Connection、Keep-Alive、Upgrade连接级帧(SETTINGS、GOAWAY、PING)
reason-phrase删除(无语义)

没改什么

以下在 h2 上逐字不变,全部来自 RFC 9110:

  • 方法及其安全性/幂等性/可缓存性
  • 状态码(含三位数字与类别规则)
  • 字段语义:Content-Type、ETag、Cache-Control、Vary、Authorization、Cookie…
  • 条件请求、范围请求、缓存、认证全部规则

一个 1.1 请求与其 h2 等价物在语义上完全相同,可以无损互转——这正是代理能在两版之间转换的前提。

一个请求的形态对比

1.1:

GET /index.html HTTP/1.1
Host: example.com
Accept: text/html

h2 逻辑等价(HEADERS 帧内经 HPACK 编码的字段列表):

:method: GET
:scheme: https
:authority: example.com
:path: /index.html
accept: text/html

三处关键差异:

  1. 起始行拆成了伪头字段(: 开头)。
  2. Host 变成 :authority。
  3. 字段名必须小写——h2 中大写字母是协议错误,不是风格问题。

版本标识与协商

h2 不使用 1.1 的 Upgrade 机制协商(见下),而是靠 ALPN(TLS 扩展)在握手时直接选定:

ALPN 标识含义
h2HTTP/2 over TLS
h2cHTTP/2 over 明文 TCP
http/1.1HTTP/1.1

要点:

  • 浏览器只支持 h2(TLS),从不支持明文 h2c。规范上 h2 不强制 TLS,实践中等于强制。
  • ALPN 在 TLS 握手中完成,不增加往返——这是它取代 Upgrade 的核心优势。
  • 选定 h2 后,客户端立即发连接前言。

h2c 与 Upgrade 的废弃

RFC 7540 曾定义用 1.1 的 Upgrade: h2c 升级到明文 h2:

GET / HTTP/1.1
Host: example.com
Connection: Upgrade, HTTP2-Settings
Upgrade: h2c
HTTP2-Settings: <base64url 编码的 SETTINGS>

RFC 9113 已废弃该机制,连同 HTTP2-Settings 字段一并移除。原因:几乎无部署(浏览器不支持)、且给中间件带来额外的协议混淆面。

现状:明文 h2 只能靠先验知识(客户端已知服务端支持,直接发前言)建立,主要用于内网 gRPC 等场景。

TLS 要求

h2 over TLS 有额外硬约束(超出普通 TLS 要求):

  • MUST 使用 TLS 1.2 及以上。
  • MUST 禁用压缩与可重协商(renegotiation)。
  • 有密码套件黑名单:使用被禁套件时,端点 MAY 以 INADEQUATE_SECURITY 错误关闭连接。实践中要求前向安全 + AEAD(如 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)。
  • 服务端 MUST 支持 SNI。

代价

h2 不是纯收益,两个真实代价:

  1. TCP 层队头阻塞仍在。h2 消除了 HTTP 层的队头阻塞,但所有流共享一条 TCP 连接——一个 TCP 段丢失,内核在重传补齐前不会把后续数据交给应用,此时所有流一起卡住。丢包率高的网络下,h2 可能比多条 1.1 连接更慢。这正是 HTTP/3 存在的唯一理由。
  2. 实现复杂度剧增。状态机、流量控制、HPACK 动态表同步都可能出错,也带来了新的攻击面(如 HPACK 炸弹、RST_STREAM 洪泛的 Rapid Reset)。

下一篇:二进制分帧层。

本页目录