技术知识文章集合TECHNICAL ARCHIVE · 457 DOCUMENTS

显示模式

登录
ARCHIVE DOCUMENTNET

HTTP/2 基本概念学习笔记

所属馆藏
NET Protocol
文件格式
Markdown
原始路径
NET Protocol/04-HTTP2基本概念学习笔记
本文目录6 个章节
  1. 1. 过去和现在
  2. 2. HTTP/2
  3. 2.3 多路复用(Multiplexing)和 Stream
  4. 3. HTTP/2 与 HTTP/3 的关系
  5. 4. 总结
  6. 参考资料

HTTP/2 基本概念学习笔记

Category(分类): NET Protocol Status: 未知

本文保留原文关于 HTTP/2 二进制分帧、多路复用、HPACK、服务器推送、优先级、流重置和流量控制的学习路径,并结合 RFC 9113、RFC 9218、RFC 9114 和 QUIC 的现代说明修正过时内容。

HTTP/2 规范最初于 2015 年以 RFC 7540 发布。当前正式规范是 RFC 9113(2022),它取代了 RFC 7540。现代浏览器和服务器普遍支持 HTTP/2,但实际能否使用还取决于 TLS、ALPN、代理、CDN 和服务器配置。

HTTP/2 支持情况示意图

原文图片记录于 2018 年,具有历史参考价值,不能代表当前所有浏览器和服务器的支持比例。

作为对 HTTP/1.x 传输效率的改进,HTTP/2 在不改变 HTTP 方法、状态码、URI 和大部分首部语义的前提下,引入了二进制分帧、多路复用、首部压缩和流量控制等机制。

1. 过去和现在

HTTP/1.1 最初由 RFC 2068 于 1997 年发布,随后 RFC 2616 于 1999 年发布。后来 HTTP/1.1 的语义和消息语法被 RFC 9110、RFC 9111、RFC 9112 等新规范重新整理。HTTP/1.x 被广泛使用了很长时间,但随着网页资源数量和网络交互复杂度增加,一些传输层面的限制逐渐明显。

HTTP/1.x 早期限制示意图

HTTP/1.x 常见的性能问题包括:

  • 连接并发受客户端实现限制:早期浏览器常限制同一主机的并发连接数为 2,现代浏览器对 HTTP/1.1 通常使用更高的连接数;这属于浏览器策略,不是 HTTP 标准规定的固定值;
  • HTTP/1.1 请求级队头阻塞:同一个连接上的管线化请求和响应受到顺序限制,后面的响应可能等待前面的响应;浏览器通常通过多个 TCP 连接缓解这个问题;
  • 没有统一的首部压缩机制:HTTP/1.x 首部通常以文本表示,重复的 Cookie、User-Agent 等首部会造成额外开销。应用或代理可以使用其他压缩方式,但 HTTP/1.x 本身没有 HPACK 这样的通用机制;
  • 缺少统一的请求优先级信号:服务器可以自行调度,但 HTTP/1.x 没有像现代 HTTP Priority 那样的统一优先级机制;
  • 请求—响应模型不适合任意时刻的服务端消息:HTTP 传统上由客户端发起请求、服务端返回响应,但也可以通过长轮询、SSE、流式响应或 WebSocket 实现不同形式的推送。

HTTP/2 使用以下技术改善传输效率:

  • 二进制分帧;
  • 多路复用;
  • HPACK 首部压缩;
  • 流级和连接级流量控制;
  • Stream 重置;
  • 可扩展的优先级机制。

需要特别注意:HTTP/2 解决了 HTTP/1.x 中一部分请求级队头阻塞,但多个 Stream 仍然共享一条 TCP 连接,因此 TCP 丢包仍可能阻塞整条 HTTP/2 连接。HTTP/3 使用 QUIC 的独立 Stream,进一步减少跨 Stream 的传输层队头阻塞。

2. HTTP/2

HTTP/2 的前身是 SPDY 协议。SPDY 是 Google 主导的历史实验性应用层协议,HTTP/2 的早期草案大量借鉴了 SPDY 的设计。

HTTP/2 的目标是在维持 HTTP 语义的前提下改善传输性能:

  • HTTP 方法、状态码、URI 和大部分首部字段的语义继续保留;
  • HTTP/2 改变的是连接上的编码、分帧和传输方式;
  • 应用看到的仍然是 HTTP 请求和响应,而不是 SPDY 专有语义。

HTTP/2 的主要特性包括:

  1. 二进制帧层;
  2. 使用帧作为传输单位;
  3. 多路复用;
  4. HPACK 首部压缩;
  5. 可选的服务器推送;
  6. 流量控制;
  7. Stream 重置;
  8. 历史上的 Stream 优先级与依赖关系;
  9. 连接级和 Stream 级错误处理。

HTTP/2 是否强制使用 HTTPS?

HTTP/2 规范本身没有要求必须使用 TLS。HTTP/2 存在明文 h2c 模式,但浏览器通常只支持通过 TLS ALPN 协商的 HTTP/2,因此面向浏览器的 HTTP/2 一般表现为 HTTPS。

HTTP/2 使用 TCP;不要把 HTTP/2 和 HTTP/3 混为一谈:

HTTP/1.1 → TCP
HTTP/2   → TCP
HTTP/3   → QUIC/UDP

2.1 二进制表示

在 HTTP/1.x 中,请求行和首部通常使用可读的文本格式。HTTP/2 在连接层使用二进制帧,帧头中的长度、类型、标志和 Stream 标识符都有明确的字段位置,解析时不需要依赖空格、换行等文本分隔符。

二进制分帧的主要价值是:

  • 便于可靠解析;
  • 支持不同 Stream 的帧交错传输;
  • 便于实现帧级控制;
  • 支持连接级和 Stream 级错误处理。

“二进制一定更小”并不准确。实际传输体积还取决于 HPACK、内容压缩、帧头开销和应用数据。HTTP 响应正文可以是文本、图片、视频或其他任意字节,并不因为 HTTP/2 就变成某一种二进制业务格式。

2.2 二进制分帧

HTTP/2 在 HTTP 语义和底层传输之间增加了二进制分帧层。HTTP/2 规范定义的帧被封装到 TCP 字节流中;每个帧都有固定的 9 字节帧头和可变长度的帧载荷。

HTTP/2 二进制分帧层示意图

基本帧结构如下:

 +-----------------------------------------------+
 |                 Length (24)                   |
 +---------------+---------------+---------------+
 |   Type (8)    |   Flags (8)   |
 +-+-------------+-------------------------------+
 |R|                 Stream Identifier (31)       |
 +=+=============================================+
 |                   Frame Payload (0...)      ...
 +-----------------------------------------------+
  • Length:24 位,表示帧载荷长度,不包括 9 字节帧头;
  • Type:8 位,表示帧类型;
  • Flags:8 位,具体含义由帧类型解释;
  • R:保留位,发送时必须为 0,接收时通常忽略;
  • Stream Identifier:31 位 Stream 标识符;
  • 帧的最大载荷长度受 SETTINGS_MAX_FRAME_SIZE 限制,默认值通常为 16,384 字节,允许的最大值为 16,777,215 字节。

RFC 7540 基础规范定义了 10 种基础帧类型:

  • DATA:传输请求或响应内容;
  • HEADERS:传输首部;
  • PRIORITY:旧版优先级信号,当前语义已被弃用;
  • RST_STREAM:终止一个 Stream;
  • SETTINGS:协商连接参数;
  • PUSH_PROMISE:声明服务端推送;
  • PING:测量连接往返时间或确认连接可用;
  • GOAWAY:优雅关闭连接;
  • WINDOW_UPDATE:更新流量控制窗口;
  • CONTINUATION:继续传输首部块。

HTTP/2 还允许扩展帧类型,因此“规范一共只有 10 种帧”应理解为基础规范的 10 种帧,而不是所有实现永远只能使用这 10 种。

一个 HTTP/2 请求在逻辑上仍然包含方法、路径、首部和内容,只是它们被编码到 HEADERS、CONTINUATION 和 DATA 等帧中:

HTTP/2 请求示意图

2.3 多路复用(Multiplexing)和 Stream

RFC 9113 将 Stream 描述为:在一个 HTTP/2 连接中,由客户端和服务器交换的独立帧序列。Stream 是逻辑概念,不是额外的一条 TCP 连接。

HTTP/2 Stream 示意图

一个 HTTP/2 连接可以包含多个并发 Stream。不同 Stream 的帧可以在同一条 TCP 连接中交错传输;同一个 Stream 内的帧则必须按照协议规定的顺序处理。

可以把三者理解为:

TCP 连接
  └── HTTP/2 连接
        ├── Stream 1
        │     ├── HEADERS
        │     └── DATA
        ├── Stream 3
        │     ├── HEADERS
        │     └── DATA
        └── Stream 5
              ├── HEADERS
              └── DATA

多路复用示例

假设 TCP 连接已经建立,客户端需要同时发起两个请求。HTTP/1.1 可能需要多个连接,HTTP/2 则可以为它们创建两个 Stream:

HTTP/2 多路复用的逻辑示意图

实际传输时,帧仍然会沿着一条 TCP 字节流依次发送,但来自不同 Stream 的帧可以交错:

HEADERS(stream 1)
HEADERS(stream 3)
DATA(stream 3)
DATA(stream 1)
DATA(stream 3)

这里的“并发”是多个 Stream 的进展可以交错进行,并不意味着多个帧在同一条 TCP 字节流上物理同时到达。

需要注意:

  1. 不同 Stream 的帧可以交错传输;
  2. 同一个 Stream 内部的帧顺序必须保持;
  3. 初始请求或响应首部通常先于其 DATA,但尾部首部可以在 DATA 之后出现;
  4. CONTINUATION 必须按照首部块规则紧跟相关首部帧;
  5. 不同 Stream 的完成顺序可以不同,服务端可以根据调度策略先发送更重要的 Stream。

多路复用减少了 HTTP/1.1 为了并发而创建大量 TCP 连接的需求,也减少了 HTTP/1.1 请求级队头阻塞。但它没有消除 TCP 层队头阻塞:一旦 TCP 某个数据包丢失,后续字节需要等待重传,多个 HTTP/2 Stream 可能一起受影响。

HTTP/3 将 HTTP 映射到 QUIC 的独立 Stream,某个 Stream 的丢包通常不会阻塞其他 Stream,但单个 Stream 内部仍然是有序可靠传输。

HTTP/1.1 与 HTTP/2 的性能示意

下面的图片是原文历史性能示意,具体收益会受到网络、缓存、资源数量、服务端实现和浏览器版本影响:

HTTP/1.1 性能示意

HTTP/2 性能示意

过去的 HTTP 性能优化经常关注带宽和延迟。对包含大量小资源的网页来说,连接建立、往返延迟、请求调度和队头阻塞都可能影响首屏时间。

网络带宽与延迟关系示意

TCP 慢启动会影响新建连接在短时间内能够发送的数据量。HTTP/2 让多个 Stream 共享一条 TCP 连接,通常可以减少重复握手和慢启动开销,但也带来共享 TCP 拥塞状态和 TCP HOL 的影响。因此不能简单断言 HTTP/2 在所有网络条件下都比 HTTP/1.1 快,更不能把历史 Demo 的结果当成固定结论。

对于 HTTP/2,通常不再需要为了并发而进行 HTTP/1.1 时代的域名分片、资源拼接和大量 Sprite;但是否合并资源、是否预加载,仍应根据缓存粒度、构建工具、网络和实际性能数据决定。

2.4 首部压缩:HPACK

HTTP 的语义是无状态的,单个请求应携带服务端理解该请求所需的首部信息。但这并不意味着所有业务状态都要放在每个请求中,也不意味着身份信息只能放在 Cookie 中。Cookie、Session、Token 等是应用层状态管理方案,安全性主要依赖 TLS、认证和权限设计。

HTTP/1.x 没有统一的首部压缩机制。大量请求经常重复携带 Cookie、User-Agent、Accept 等首部,会造成额外开销。HTTP/2 使用 HPACK(RFC 7541)压缩首部字段:

HPACK 首部压缩示意图

HPACK 使用静态表、动态表和索引表示法:

  • 静态表预先定义常见首部字段和值;
  • 动态表在连接两端维护近期出现的首部字段;
  • 后续首部块可以使用索引引用已有条目;
  • 无法或不适合索引的字段可以直接传输;
  • 敏感字段可以使用不加入动态表的表示方式。

首部表不是“每个首部只发送一次”。条目可能被淘汰、连接可能重新建立、服务端可能选择不索引某些字段,代理和客户端也可能拥有不同的压缩状态。

HPACK 首部表示意图

HPACK 的动态表状态通常与一条 HTTP/2 连接绑定,不应跨连接假定双方仍然拥有相同的表。HPACK 只压缩首部,不压缩响应正文;正文压缩仍可使用 gzip、Brotli 等内容编码。

2.5 服务器推送

HTTP/2 Server Push 是一种可选能力:当客户端请求资源 X 时,服务端可以通过 PUSH_PROMISE 预先声明并发送客户端可能需要的资源 Z,而不必等待客户端明确请求 Z。

原文将其称为“缓存推送”,这个称呼便于理解,但不是正式的协议名称。客户端可以通过 HTTP/2 设置禁用服务器推送,也可以在不需要时使用 RST_STREAM 取消对应的推送 Stream。

传统流程是:

HTTP/1.x 传统资源加载示意

网页先请求 Document,浏览器解析 Document 后,再发现 CSS、JavaScript、图片等资源并发起后续请求。过去常见的优化方式包括内联关键 CSS、合并资源、CSS Sprite、压缩 JavaScript 等:

HTTP/2 之前的资源优化方式

HTTP/2 Server Push 的设想是:服务端在返回 Document 时,主动推送它预测客户端会需要的资源:

HTTP/2 Server Push 示意

但需要注意以下限制:

  • 推送是可选能力,客户端可以禁用或取消;
  • 推送资源是否进入缓存,取决于缓存策略、响应首部和客户端实现,并非必然;
  • 服务端预测错误时,会浪费带宽并挤占真正重要资源;
  • 客户端已经缓存资源时,重复推送可能反而降低性能;
  • Server Push 是连接级/协议级行为,不等同于 CDN 缓存,也不能替代 CDN;
  • 主流浏览器已经禁用或移除了 HTTP/2 Server Push 的实际支持,Chrome/Chromium 等浏览器不再将它作为常规网页优化方案。

原文提到的 cache-digest 是历史草案,并没有成为当前通用标准。现代网页通常优先考虑:

  • Link: <...>; rel=preload
  • 103 Early Hints
  • 合理的 Cache-Control 和 CDN 缓存;
  • 更准确的资源依赖分析;
  • 根据真实性能数据决定是否预加载。

HTTP/2 仍然可以在非浏览器或特定基础设施中使用 Server Push,但新项目不应默认依赖浏览器支持。

服务器推送也不能减少或替代 CDN。CDN 可以通过地理位置、边缘缓存和接近用户的节点减少网络往返,而 HTTP/2 主要改善连接内的传输组织方式,两者解决的问题不同。

2.6 优先级与依赖关系

HTTP/2 早期规范使用 Stream 依赖树和权重描述优先级:某个 Stream 可以依赖另一个 Stream,服务端根据权重进行调度。客户端还可以通过 PRIORITY 帧动态调整这些信息。

这部分内容需要加上版本说明:RFC 9113 已弃用 RFC 7540 的依赖树、权重和旧优先级语义,保留相关线格式主要是为了兼容。现代 HTTP 优先级应参考 RFC 9218:

  • 使用 Priority 首部表达可扩展优先级;
  • 在 HTTP/2 中可以使用 PRIORITY_UPDATE 扩展帧;
  • 具体调度仍由服务器实现决定,客户端发送优先级不代表服务器必须按该顺序发送。

优先级可以帮助服务端在资源有限时调度重要资源,但不能保证页面一定按某个固定顺序加载,也不能替代缓存和资源依赖设计。

2.7 Stream 可重置

HTTP/1.x 中,如果一个请求或响应正在传输,取消它通常需要关闭连接,或者依赖客户端关闭写方向等实现行为。关闭整个 TCP 连接会影响该连接上的其他请求。

HTTP/2 可以通过 RST_STREAM 终止单个 Stream,而不必关闭整个 TCP 连接:

  • 取消不再需要的响应;
  • 终止发生错误的请求;
  • 释放该 Stream 的传输资源。

RST_STREAM 不是事务回滚。服务端可能已经收到请求内容或执行了业务逻辑,尤其是 POST、支付和订单操作,不能因为客户端重置 Stream 就认为业务一定没有发生。

2.8 流量控制

HTTP/2 同时具有两级流量控制:

  1. Stream 级窗口:限制某个 Stream 上可发送的 DATA 数据量;
  2. Connection 级窗口:限制整个 HTTP/2 连接上所有 Stream 的 DATA 总量。

双方通过 WINDOW_UPDATE 增大对应窗口。只有 DATA 帧受到流量控制,HEADERS、RST_STREAM、SETTINGS 等控制帧不受 DATA 窗口限制。

接收端需要根据自身缓冲能力更新窗口;发送端在窗口耗尽时必须暂停发送对应的数据。流量控制用于防止快速发送方压垮接收方,但它与 TCP 拥塞控制是两套不同的机制:

  • TCP 拥塞控制关注网络路径能承受多少数据;
  • HTTP/2 流量控制关注接收端和 Stream 能处理多少数据。

3. HTTP/2 与 HTTP/3 的关系

HTTP/2 和 HTTP/3 都保留了 HTTP 的方法、状态码和大部分语义,但底层传输方式不同:

项目HTTP/2HTTP/3
底层传输TCP + TLS(常见)QUIC + UDP,QUIC 内置 TLS 1.3 握手
多路复用多个 Stream 共享一条 TCP 字节流多个独立 QUIC Stream
TCP 层 HOL仍然存在不使用 TCP,减少跨 Stream HOL
首部压缩HPACKQPACK
HTTP/2 Server Push规范支持但浏览器支持很少协议仍可表达,但浏览器支持和实际使用同样有限
连接迁移依赖 TCP 连接QUIC 支持连接迁移,具体受网络和实现限制

HTTP/3 并不是 HTTP/2 的简单换端口版本,而是把 HTTP 映射到 QUIC 后重新定义了部分连接、Stream 和首部压缩行为。

4. 总结

HTTP/2 能带来的主要好处包括:

  • 使用二进制分帧,便于解析和控制;
  • 通过多个 Stream 复用一个连接,减少 HTTP/1.1 为并发而建立的大量连接;
  • 通过 HPACK 减少重复首部传输,但不保证所有请求都获得相同压缩收益;
  • 通过 Stream 重置取消单个传输,不必关闭整个连接;
  • 通过 Stream 级和 Connection 级流量控制保护接收端;
  • 可以使用优先级机制辅助服务器调度资源;
  • 可选的 Server Push 在协议上仍存在,但已不适合作为现代浏览器网页的默认优化方案;
  • HTTP/2 仍然受到 TCP 层队头阻塞影响,HTTP/3/QUIC 在这方面进一步改进。

HTTP/2 与 CDN 并不互相替代。CDN 主要减少地理距离和缓存访问延迟,HTTP/2 主要改善连接内的帧组织和资源传输,实际系统通常需要结合 CDN、缓存、TLS、连接复用和性能监控共同优化。

参考资料

  1. RFC 9113:HTTP/2
  2. RFC 7540:HTTP/2(历史规范)
  3. RFC 7541:HPACK
  4. RFC 9218:HTTP Extensible Priorities
  5. RFC 9114:HTTP/3
  6. RFC 9000:QUIC
  7. RFC 8297:103 Early Hints
  8. HTTP/2 Server Push 的浏览器现状
  9. MDN:HTTP/2
457 DOCUMENTS · 10 COLLECTIONS
ARCHIVE SEARCH457 篇文章

SEARCH GUIDE

输入关键词开始搜索

支持搜索文章标题、所属分类和原始文档路径。

按分类浏览

10 COLLECTIONS