HTTP/1.1 vs HTTP/2

HTTP/1.1 vs HTTP/2:共享语义,主要区别在传输表达(二进制分帧、多路复用、头压缩等)。

#type / synthesis #status / growing #resource / http #tech / network #protocol / http

[!info] related notes

HTTP/1.1 vs HTTP/2

把 HTTP/1.1 和 HTTP/2 放在一起看,最重要的一句话是:

它们大体共享同一套 HTTP 语义,主要区别在“线上怎么传”。
方法、状态码、URI、字段这些“HTTP 是什么”的部分,属于通用语义;HTTP/1.1 和 HTTP/2 更多是在定义“这些语义怎样编码、分帧、复用、管理连接”。RFC 9110 定义了跨版本共享的 HTTP 语义,RFC 9112 定义 HTTP/1.1 的消息语法与连接管理,RFC 9113 定义 HTTP/2 如何用帧和流来表达同样的 HTTP 语义。(IETF Datatracker)

先抓主线

HTTP/1.1 的核心模型是:文本报文 + 持久连接 + 请求/响应顺序关联
HTTP/2 的核心模型是:二进制分帧 + 单连接多流复用 + 头部压缩。HTTP/2 不是“换了一套语义”,而是“把同样的 HTTP 语义搬到更高效的传输表达上”。RFC 9113 直接把 HTTP/2 描述为 “HTTP semantics 的 optimized transport”。(IETF Datatracker)

一、HTTP/1.1 到底是什么

HTTP/1.1 是一个无状态的应用层请求/响应协议。在线上,一个 HTTP/1.1 消息的基本形状是:

start-line
header fields
空行
可选的 message-body

RFC 9112 给出的语法就是 HTTP-message = start-line CRLF *( field-line CRLF ) CRLF [ message-body ];请求和响应在语法上几乎一样,只是 start-line 不同:请求用 request-line,响应用 status-line。(IETF Datatracker)

举个最典型的 HTTP/1.1 请求:

GET /index.html HTTP/1.1
Host: example.com
User-Agent: curl/8.0
Accept: */*

对应响应大概会像这样:

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 123

<html>...</html>

这里最关键的是:HTTP/1.1 是文本可读的。你拿 telnetnc、抓包工具都能直接看到请求行、状态行、头字段和正文边界。这个“人类可读”是它的优点,也是后来性能优化受限的原因之一。其消息解析规则、起始行和状态行格式都由 RFC 9112 明确规定。(IETF Datatracker)

二、HTTP/1.1 的连接管理:为什么会有 keep-alive、chunked、pipelining

HTTP/1.1 相比更早版本,一个大改进是持久连接。在 HTTP/1.1 里,连接默认可以复用;不想复用时,要显式用 Connection: close 表示当前响应后关闭。RFC 9112 还要求:若想保持连接持久化,连接上的每条消息都必须有自描述的长度,否则下一条消息就没法判断从哪开始。(IETF Datatracker)

于是 HTTP/1.1 必须非常在意“消息体长度怎么判断”。常见方式有三种:

  1. Content-Length:正文长度已知。
  2. Transfer-Encoding: chunked:正文长度事先未知,就一块块发。
  3. 少数响应用“连接关闭”作为结束标志。

RFC 9112 明确规定了 Transfer-EncodingContent-Length 的优先级、chunked 的解码规则,以及在没有显式长度时何时只能靠关闭连接来界定消息结束。(IETF Datatracker)

chunked 是 HTTP/1.1 很关键的一招。它解决的是:服务器在生成内容时,一开始不知道总长度,但又不想等全部内容生成完再发。于是可以边算边发:

HTTP/1.1 200 OK
Transfer-Encoding: chunked

7
Mozilla
9
Developer
7
Network
0

这不是内容编码,而是消息分块传输编码。RFC 9112 明确说 Transfer-Encoding 是消息属性,不是表示层属性;chunked 在 HTTP/1.1 里是消息定界的重要手段。(IETF Datatracker)

还有一个常被提起但实际效果一般的机制是 pipelining。HTTP/1.1 允许客户端在持久连接上连续发多个请求,不必等前一个响应回来再发下一个;但服务器必须按收到请求的顺序返回响应。这就导致一个问题:前面的响应慢,后面的即使已经准备好,也不能先回,这就是 HTTP/1.1 的应用层队头阻塞。(IETF Datatracker)

RFC 9113 在回顾 HTTP/1.1 的问题时说得很直白:HTTP/1.1 的 pipelining 只部分解决了并发问题,而且仍然遭受application-layer head-of-line blocking;因此 HTTP/1.x 客户端通常会开多个 TCP 连接去并行请求。(IETF Datatracker)

三、HTTP/1.1 的本质瓶颈在哪里

HTTP/1.1 的瓶颈,核心不在“文本慢”这一个点,而在三个叠加问题:

第一,重复头字段太多。同一个站点上连续请求 50 个资源,CookieUser-AgentAccept 之类字段会反复发送。(IETF Datatracker)

第二,并发要靠多连接。因为同一连接上的 pipelining 很难彻底发挥作用,浏览器往往要靠“多条 TCP 连接并行”去榨性能。这样会带来额外握手、拥塞竞争、上下文维护和中间设备压力。RFC 9113 明确提到,HTTP/1.x 时代客户端会使用多个连接做并发。(IETF Datatracker)

第三,消息语法和连接控制耦合得很紧。你需要靠 ConnectionKeep-AliveUpgradeTransfer-Encoding 等机制描述连接和消息边界。这个模型可扩展,但复杂,也容易被代理、中间件、请求走私等问题放大。RFC 9112 对 Transfer-EncodingContent-Length 的组合、错误 framing、消息不完整等都给了大量安全与兼容性要求。(IETF Datatracker)

四、HTTP/2 到底改了什么

HTTP/2 的设计目标非常明确:不改 HTTP 语义,只改传输表达方式。RFC 9113 说它通过字段压缩同一连接上的多个并发交换,更高效地利用网络资源、降低延迟;同时它还通过二进制消息分帧提升了消息处理效率。(IETF Datatracker)

HTTP/2 仍然是应用层协议,而且 HTTP/2 仍然跑在 TCP 上。这一点很重要,因为很多人容易把 HTTP/2 和“基于 UDP”的 HTTP/3 混在一起。RFC 9113 明确写了:HTTP/2 是运行在 TCP 连接之上的 connection-oriented application-layer protocol。(IETF Datatracker)

HTTP/2 的最小通信单位不再是“整条文本报文”,而是 frame(帧)。每个请求/响应交换被放进一个 stream(流)。RFC 9113 的定义是:stream 是 HTTP/2 连接内客户端和服务器之间独立的、双向的帧序列。同一条 HTTP/2 连接上可以同时打开多个流,而且不同流的帧可以交错发送。(IETF Datatracker)

这就是 HTTP/2 最核心的价值:多路复用
在 HTTP/1.1 里,你经常要靠多条 TCP 连接并发;在 HTTP/2 里,一条连接里就能同时跑 stream 1、3、5、7…… 多个请求。RFC 9113 还明确说:一个被阻塞或停滞的请求/响应,不会阻止其他流继续推进。(IETF Datatracker)

五、HTTP/2 的帧和流,具体怎么理解

HTTP/2 把请求/响应拆成几类帧。最核心的是:

  • HEADERS:放请求头或响应头
  • DATA:放正文
  • SETTINGS:协商参数
  • WINDOW_UPDATE:流控窗口更新
  • RST_STREAM:中止单个流
  • GOAWAY:关闭整个连接
  • PUSH_PROMISE:服务器推送
  • PING:探活

RFC 9113 直接说明:HEADERSDATA 帧构成 HTTP 请求和响应的基础。(IETF Datatracker)

一条典型的 HTTP/2 GET 请求,概念上更像这样:

HEADERS (stream 1)
  :method = GET
  :scheme = https
  :authority = example.com
  :path = /index.html
  user-agent = ...
  accept = ...
  END_HEADERS
  END_STREAM

因为 GET 通常没有请求体,所以 HEADERS 本身就带 END_STREAM
而一个带正文的响应,会是:

HEADERS (stream 1)
  :status = 200
  content-type = text/html
  END_HEADERS

DATA (stream 1)
  ...

DATA (stream 1)
  ...
  END_STREAM

RFC 9113 规定:HTTP/2 用 DATA 帧承载消息内容;一个请求/响应交换完整消耗一个 stream,结束标记靠 END_STREAM,而不是 HTTP/1.1 那种 chunked 或“靠连接断开”来界定。(IETF Datatracker)

六、HTTP/2 为什么不再需要 chunked

这是一个非常实用的区别。

HTTP/1.1 需要 chunked,是因为正文长度有时事先不知道,而接收方又必须知道正文什么时候结束。
HTTP/2 里,这个问题由帧层解决了:正文天然就是一串 DATA 帧,最后一个带 END_STREAM。RFC 9113 明确写了:HTTP/2 用 DATA 帧承载消息内容,HTTP/1.1 中定义的 chunked transfer encoding 不能用于 HTTP/2。(IETF Datatracker)

所以你可以把它理解成:

  • HTTP/1.1:先有“文本报文”,再想办法告诉你 body 多长
  • HTTP/2:先有“帧”和“流”,body 天然就是流上的一段帧序列

七、HTTP/2 的头部为什么更省

HTTP/2 引入了 HPACK 头部压缩。RFC 7541 规定,HPACK 不是普通的 gzip,而是专门为 HTTP/2 头字段设计的一套压缩表示:它把头字段看成有序的 name-value 列表,通过静态表、动态表Huffman 编码来减少冗余。(IETF Datatracker)

它的意义很大。像 Cookie、认证信息、常见头字段名,在 HTTP/1.1 里会一遍遍原样发送;在 HTTP/2 里,很多可以变成“引用表项”或者更短的编码。RFC 7541 还特别提到,SPDY 早期用 DEFLATE 压缩头部时暴露过 CRIME 一类安全问题,而 HPACK 的设计目标之一就是减少已知攻击面并保持有界内存需求。(IETF Datatracker)

所以 HTTP/2 的“更快”很大一部分并不是正文压缩得更厉害,而是大量重复头部不再反复裸传。(IETF Datatracker)

八、HTTP/2 的头字段规则也变了

HTTP/2 里有一组特殊的伪头字段,名字以冒号开头:

  • :method
  • :scheme
  • :authority
  • :path
  • 响应里的 :status

RFC 9113 规定了这些字段的含义和必需性:普通请求必须带 :method:scheme:path,通常也要有 :authority;如果 :authority 在,接收方不能再靠 Host 去判断目标 URI。(IETF Datatracker)

另一个很容易踩坑的点是:HTTP/2 字段名必须小写。RFC 9113 把包含大写字段名的消息视为 malformed,并明确要求构造 HTTP/2 消息时把字段名转成小写。(IETF Datatracker)

再一个关键区别是:HTTP/2 不允许连接特定头字段继续沿用 HTTP/1.x 的那套玩法。RFC 9113 明确说,HTTP/2 不使用 Connection 字段来声明 connection-specific headers;ConnectionProxy-ConnectionKeep-AliveTransfer-EncodingUpgrade 都不能出现在 HTTP/2 消息里,否则消息是 malformed。唯一例外是 TE 可以出现,但值只能是 trailers。(IETF Datatracker)

这意味着:HTTP/2 把很多“连接管理语义”从 HTTP/1.1 的文本头字段里抽了出来,改放到帧层和连接状态机里处理。(IETF Datatracker)

九、HTTP/2 的流控、取消、优雅关闭

HTTP/2 因为一条连接里可以有很多流,所以必须有更明确的流量控制。RFC 9113 规定:只有 DATA 帧受 flow control 约束;而且同时存在stream 级窗口connection 级窗口。接收方通过 WINDOW_UPDATE 告诉发送方还能再发多少。这样做是为了让接收方在资源受限时,仍然能让某些流继续推进,而不是被单个流拖死。(IETF Datatracker)

HTTP/2 的错误处理也更细:

  • 单个流出问题:用 RST_STREAM
  • 整条连接要收尾:用 GOAWAY

RFC 9113 规定 RST_STREAM 用于立即终止一个流;GOAWAY 用于告知对端不要再在这条连接上开新流,并指明“最后一个可能已被处理的流 ID”,方便安全重试。(IETF Datatracker)

这比 HTTP/1.1 更细腻。HTTP/1.1 里,一条连接上请求顺序绑定得更紧,连接异常常常意味着后续多个请求的状态都变得模糊。HTTP/2 至少能把“流级错误”和“连接级错误”分开。(IETF Datatracker)

十、HTTP/2 是否彻底消灭了队头阻塞

没有,只是消灭了一部分

HTTP/2 解决了 HTTP/1.1 的应用层队头阻塞:一个流慢,不必阻止别的流返回。RFC 9113 明确写到,HTTP/1.1 的 pipelining 仍然存在应用层 HOL blocking,而 HTTP/2 的多流复用使被阻塞的流不会阻止其他流推进。(IETF Datatracker)

但 HTTP/2 没有解决 TCP 层的队头阻塞。RFC 9113 也明确提醒:TCP head-of-line blocking 并没有被 HTTP/2 解决。也就是说,只要底层 TCP 某个报文段丢了,后续字节即使属于别的 stream,也得等 TCP 重传后才能按序交给上层。(IETF Datatracker)

所以你可以把区别记成:

  • HTTP/1.1:连接内的“请求顺序”会卡住后面的响应
  • HTTP/2:流之间可以并发,但底层 TCP 丢包仍会让整条连接暂时等待

十一、HTTP/2 怎么开始协商

现代 HTTPS 场景里,HTTP/2 通常通过 TLS + ALPN 协商。RFC 9113 规定,HTTP/2 over TLS 使用的 ALPN 标识是 "h2"。TLS 完成后,双方还要发送 connection preface;客户端前言以固定字符串 PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n 开头,后跟 SETTINGS 帧;服务器的前言则从 SETTINGS 帧开始。(IETF Datatracker)

一个很值得更新认知的点是:很多旧教程会讲 Upgrade: h2c。但在 RFC 9113 里,h2c 这个 Upgrade token 和 HTTP2-Settings 头字段已经被标成 obsolete;对于 http URI,HTTP/2 支持现在只能通过out-of-band 的 prior knowledge 来发现。也就是说,新的规范文本不再鼓励你走老式的 HTTP/1.1 Upgrade 到 h2c。(IETF Datatracker)

再补一条常见误解:HTTP/2 不等于“必须 HTTPS”。协议层面,HTTP/2 可以有 cleartext 版本;但对 https URI,规范要求用 TLS 和 ALPN,而这也是现实部署的主流。RFC 9113 还指出,cleartext 版本对跨协议攻击的防护更弱。(IETF Datatracker)

十二、把两者放在一张脑图里

可以把 HTTP/1.1 和 HTTP/2 这样对照着记:

1)语义层面
两者共享 HTTP 语义:方法还是 GET/POST,状态码还是 200/404,缓存、条件请求、内容协商这些核心概念都没变。变的是报文表达和连接机制。(IETF Datatracker)

2)线上格式
HTTP/1.1 是文本报文,start-line + headers + body;HTTP/2 是二进制帧,HEADERS/DATA/... 组成 stream。(IETF Datatracker)

3)并发方式
HTTP/1.1 想并发,常靠多 TCP 连接,pipelining 受响应顺序约束;HTTP/2 在一条连接里开多个并发流,帧可以交错发送。(IETF Datatracker)

4)正文定界
HTTP/1.1 主要靠 Content-Lengthchunked、或连接关闭;HTTP/2 靠 DATA 帧和 END_STREAM。(IETF Datatracker)

5)头部成本
HTTP/1.1 大量重复头字段裸传;HTTP/2 用 HPACK 压缩,靠静态/动态表复用头字段。(IETF Datatracker)

6)连接语义
HTTP/1.1 里 ConnectionKeep-AliveTransfer-EncodingUpgrade 很重要;HTTP/2 里这些 connection-specific headers 基本被禁止,连接语义改由帧层和状态机表达。(IETF Datatracker)

7)队头阻塞
HTTP/1.1 有明显的应用层 HOL;HTTP/2 去掉了这层问题,但仍受 TCP HOL 影响。(IETF Datatracker)

十三、几个容易被旧教程带偏的点

第一,HTTP/2 不是“HTTP/1.1 加 gzip”。它是完整的二进制分帧协议,头部压缩用的是 HPACK,不是简单把整条请求 gzip 一下。(IETF Datatracker)

第二,HTTP/2 不是“消息顺序乱了”。乱的是“不同流的帧可以交错”,但每个 stream 自己仍有严格状态和顺序要求。(IETF Datatracker)

第三,HTTP/2 不是“彻底没有阻塞”。它只是解决了 HTTP/1.1 的请求/响应级阻塞,没解决 TCP 级阻塞。(IETF Datatracker)

第四,优先级不是现在最该死记的点。RFC 9113 明确说,这个版本把 RFC 7540 的 priority signaling scheme 标成了 deprecated。很多老资料大讲 priority tree,但按现行规范语境,它已经不是 HTTP/2 最核心的学习入口了。(IETF Datatracker)


一句话收尾:

HTTP/1.1 的世界观是“一个文本请求对应一个文本响应,连接负责串起来”;HTTP/2 的世界观是“同一条 TCP 连接里有很多独立流,请求和响应被拆成帧并发传输”。
理解了“文本报文 vs 二进制分帧”“顺序响应 vs 多流复用”“裸头字段 vs HPACK 压缩”这三组对照,HTTP/1.1 和 HTTP/2 的核心差别就基本吃透了。(IETF Datatracker)

创建于 2026/3/13 更新于 2026/5/27