解读 HTTP/1.1、HTTP/2 与 HTTP/3
Category(分类): NET Protocol Status: 未知
HTTP/2 相比 HTTP/1.1 在连接复用、二进制分帧和首部压缩等方面进行了改进,通常可以减少请求排队和重复首部带来的开销。但 HTTP/2 并不是在所有场景下都一定更快,也不能完全替代前端性能优化。HTTP/3 则将 HTTP 语义运行在 QUIC 之上,主要解决 HTTP/2 依赖 TCP 时产生的连接级队头阻塞,并提供更灵活的连接迁移能力。
本文主要介绍 HTTP/1.1、HTTP/2 和 HTTP/3 的设计差异。文中所说的性能收益取决于网络 RTT、丢包率、资源数量、资源大小、缓存、服务器配置和客户端实现,不能简单用一个固定百分比衡量。
一、HTTP/1.1 的常见问题
HTTP/1.1 本身并不是“不可用”的协议,它仍然被大量系统使用。但在大量小资源、较高 RTT 或存在丢包的网络环境中,以下问题会限制性能:
- 同一连接上的请求排队和队头阻塞;
- 缺少通用的首部压缩,重复首部带来额外开销;
- HTTP 本身不提供加密和身份认证;
- 没有标准化的服务器推送机制。
1. 请求排队与队头阻塞
虽然网络带宽不断提高,但网络延迟还会受到物理距离、路由、拥塞、DNS、连接建立和服务器处理时间等多种因素影响。HTTP/1.1 中,同一持久连接上的请求可能需要排队,队首请求没有完成时,后续请求的响应也可能受到影响,这就是应用层的队头阻塞(Head-of-Line Blocking,HOL Blocking)。
HTTP/1.1 支持管道化(pipelining),允许客户端在没有收到前一个响应时继续发送后续请求,但响应必须按照请求顺序返回,队首响应延迟仍会阻塞后续响应。由于中间设备和浏览器对管道化的支持、兼容性和部署体验不理想,现代浏览器通常更多使用多个持久连接来提高并发度。
旧版浏览器经常会对同一主机的并发连接数设置上限,例如常见的 6 个连接,但具体数量会随浏览器、协议版本、代理和配置变化。HTTP/2 和 HTTP/3 通常可以在一个连接上复用多个流,因此不应把“6 个连接”当成固定的现代浏览器规则。
为了缓解 HTTP/1.1 下的请求排队,过去常见的做法包括:
- 域名分片:将资源分散到多个域名,以绕过单个主机的连接数限制。但在 HTTP/2 和 HTTP/3 中,域名分片可能破坏连接复用、增加握手和拥塞控制开销,因此需要根据实际情况评估。
- 合并小文件:例如使用雪碧图(Spriting)将多张小图合并,再通过 CSS 或 JavaScript 定位使用。它可以减少请求数,但会降低单个资源的缓存粒度。
- 资源内联(Inlining):将小图片或其他资源直接嵌入 CSS、HTML 或脚本中,减少请求次数,但可能增大主文档并影响缓存。
- 文件合并(Concatenation):将多个较小的 JavaScript 文件打包为一个文件。文件发生局部修改时,整个合并文件可能需要重新下载,因此现代构建工具通常会结合代码分割和长期缓存使用。
这些优化是特定网络条件下的工程手段,并不是所有项目都应该无条件采用。
2. 无状态语义与首部开销
HTTP 的无状态性是指每个请求在语义上都应携带处理该请求所需的信息,服务器不会仅依赖上一个请求来理解当前请求。这并不意味着每个请求都要新建 TCP 连接:HTTP/1.1 默认支持持久连接,同一 TCP 连接可以承载多个请求。
Cookie、Authorization、Accept、User-Agent 等请求首部可能在多个请求中重复出现;响应中也可能重复出现 Cache-Control、Content-Type、Server 等字段。对于请求体很小的场景,首部占比确实可能较高,增加传输开销。需要注意,Server 通常是响应头,不应作为请求头示例。
HTTP/1.1 没有像 HTTP/2 的 HPACK、HTTP/3 的 QPACK 那样的通用动态首部压缩机制,因此重复首部的开销更明显。Cookie 还可能随着业务信息增加而变得很大,实际应用中应控制 Cookie 的数量和大小。
3. HTTP 本身不提供加密
HTTP/1.1 的协议语义本身不提供加密、完整性保护和身份认证。直接使用 http:// 时,网络中的攻击者可能窃听或篡改内容,也无法通过 HTTP 本身确认服务器身份。
HTTP/1.1 也可以运行在 TLS 之上,即 HTTPS。HTTPS 通过 TLS 提供加密、完整性保护,并通常验证服务器证书。因此,不能简单地说“所有 HTTP/1.1 都是明文”,应区分 HTTP 协议语义和承载它的 TLS 连接。
4. 没有标准化的服务器推送
HTTP/1.1 没有 HTTP/2 那样的标准服务器推送流机制。服务器可以使用缓存预热、Link: preload、103 Early Hints 等方式帮助客户端提前发现资源,但这些机制与 HTTP/2 Server Push 并不完全相同。
二、SPDY 与 HTTP/2
1. SPDY 协议
由于 HTTP/1.x 在高延迟网络中存在请求排队和首部重复等问题,Google 在 2009 年公开了 SPDY 协议。SPDY 在 HTTP 语义之下引入了二进制分帧、流复用、首部压缩和优先级等机制,通常运行在 TCP 和 TLS 之上。

SPDY 的实践验证了这些思路的可行性,后来 HTTP/2 吸收了其中很多设计。SPDY 本身已经退出历史舞台,现代实现主要使用 HTTP/2 或 HTTP/3。
2. HTTP/2 简介
HTTP/2 于 2015 年以 RFC 7540 的形式发布。当前 HTTP/2 的主要规范是 RFC 9113,HPACK 仍由 RFC 7541 定义。
HTTP/2 不是把 HTTP 语义完全重写,而是尽量保留 HTTP 方法、状态码、请求头、响应头和内容等语义,同时改变线上报文的传输格式。HTTP/2 的二进制帧格式与 HTTP/1.1 的文本报文格式并不兼容,需要通过 ALPN、Upgrade 或其他协商方式确定协议版本。
HTTP/2 的主要目标之一是允许同一连接承载多个并发的请求和响应,但协议并不强制每个 origin 只能建立一个连接。客户端和服务器仍可能因为并发流限制、连接策略、故障隔离或其他原因使用多个连接。
三、HTTP/2 的主要特性
1. 二进制分帧
HTTP/2 使用二进制帧传输协议控制信息和 HTTP 消息,不再直接传输 HTTP/1.1 那样的文本请求行和首部行。二进制格式主要有利于解析、边界识别和多路交错传输,并不意味着所有数据都会因为二进制编码而自动变小。
HTTP/2 常见的帧包括:
HEADERS:传输首部块;CONTINUATION:延续较大的首部块;DATA:传输请求或响应内容;SETTINGS:协商连接参数;WINDOW_UPDATE:更新流量控制窗口;RST_STREAM:终止单个流。
一个 HTTP 请求或响应可以由一个或多个消息组成,消息又由一个或多个帧承载。帧带有流标识符,来自不同流的帧可以在同一个 TCP 连接中交错发送;但是同一个流中的帧仍需要按顺序处理,首部块中的 CONTINUATION 帧也必须保持规定的连续顺序。
HTTP/2 仍然保留 HTTP 的首部和内容语义,只是将这些信息拆分到不同的二进制帧中,并不意味着“Header + Body”在语义上完全消失。

2. HPACK 首部压缩
HTTP/2 使用 HPACK 压缩首部。HPACK 不是简单地对每个请求独立使用 gzip,而是让编码端和解码端维护静态表和动态表,并用索引引用重复的首部字段。
HPACK 主要包括:
- 静态表:预先定义常见的首部名称和值;
- 动态表:连接过程中根据已发送的首部字段逐步更新,并受到表大小限制;
- 索引表示:直接引用表中的字段;
- 字面量表示:直接发送新的字段名称或值,可以选择是否加入动态表;
- Huffman 编码:可用于压缩字符串字面量,整数使用 HPACK 定义的变长整数编码。
动态表并不是永久不变的字典。新条目可能被插入,旧条目可能因为容量限制被逐出,编码端还可以选择不索引敏感字段。首部压缩比例取决于请求的重复程度和字段大小,没有固定的“50%~90%”保证。

3. 多路复用
HTTP/2 在一个连接中引入多个独立的流。每个请求/响应通常对应一个流,流中的消息被拆成帧后,可以与其他流的帧交错发送。这样可以减少 HTTP/1.1 中为提高并发而建立多个 TCP 连接的需要,并且通常只需要进行一次 TCP 慢启动和一次 TLS 建立。
HTTP/2 的多路复用具有以下特点:
- 一个连接可以承载多个双向流,但并发流数量受
SETTINGS_MAX_CONCURRENT_STREAMS等参数限制; - 一个流的 HTTP 层响应不必等待另一个流的响应完成;
- 连接级流量控制和流级流量控制共同限制发送量;
- 服务器仍需要根据资源、优先级和负载对各个流进行调度;
- TCP 仍然是单一有序字节流,因此 TCP 丢包会影响该连接中多个流的数据交付。

多路复用通常可以减少连接数和握手开销,但不代表所有请求都能无限并行,也不代表不同流之间完全互不影响。服务器处理能力、连接级窗口、拥塞控制和 TCP 队头阻塞仍然会造成相互影响。
HTTP/2 优先级
早期 HTTP/2 使用流依赖关系和权重表达优先级。传统优先级机制包含流依赖关系、独占标志和 1~256 的权重,并不是“每个请求拥有一个 31 位优先值,数值越小越优先”。
当前 RFC 9113 已经弃用原始的优先级依赖树机制,现代实现可以使用 HTTP Extensible Priorities(RFC 9218)中的 Priority 首部等方式表达紧急程度和增量处理偏好。优先级只是调度建议,不能保证服务器一定按照某种顺序发送。

4. Server Push
HTTP/2 规范定义了 Server Push。服务器可以在客户端请求 HTML 后,通过 PUSH_PROMISE 预先声明并发送客户端可能需要的资源,例如 CSS 或 JavaScript,从而减少客户端解析 HTML 后再发起请求的等待时间。
客户端可以通过设置禁用推送,也可以使用 RST_STREAM 取消不需要的推送。服务器推送还必须考虑缓存状态、资源是否真的需要以及带宽竞争问题;错误的推送可能浪费带宽,甚至拖慢真正重要的资源。
规范层面仍然可以描述 Server Push,但 Chrome 等主流浏览器已经基本停止支持或默认关闭该功能,现代网站很少把它作为主要性能优化手段。当前更常见的替代方式包括合理的缓存、预加载、103 Early Hints 和资源优先级控制。


5. HTTP/2 与安全性
HTTP/2 的二进制格式本身不等于加密。规范允许使用明文 HTTP/2,协议标识为 h2c;但主流浏览器通常只在 TLS 上使用 HTTP/2,使用 ALPN 协商的加密协议标识为 h2。
因此,现实中浏览器访问的 HTTP/2 网站通常是 HTTPS,但安全性主要来自 TLS,而不是来自 HTTP/2 的二进制分帧。部署 HTTP/2 时还应正确配置证书、TLS 版本、密码套件和 ALPN。

四、HTTP/2 的局限
HTTP/2 解决了 HTTP/1.1 的部分应用层问题,但它通常仍运行在 TCP 之上,因此继承了 TCP 的连接级特性。
1. 连接建立延迟
使用 HTTPS 的 HTTP/2 连接通常涉及 TCP 和 TLS 两个阶段:
- TCP 三次握手通常按约 1 个 RTT 估算;客户端可以在合适的时机将数据与最后的 ACK 一起发送,但服务器仍需要等待 TCP 状态建立;
- TLS 1.2 完整握手通常还需要约 2 个 RTT,恢复连接时可能更少;
- TLS 1.3 完整握手通常还需要约 1 个 RTT,恢复会话时可以发送 0-RTT 早期数据,但早期数据存在重放风险。
因此,不能笼统地说 HTTP/2 一定需要 3~4 个 RTT。实际延迟还受到 DNS、代理、证书验证、连接复用、缓存和网络拥塞等因素影响。
RTT(Round-Trip Time) 表示信号或报文从一端到另一端并返回所经历的往返时延。它不一定等同于“发送数据后立即收到 ACK 的时间”,因为 TCP 可能延迟确认,应用层响应也可能晚于传输层 ACK。
2. TCP 层的队头阻塞
HTTP/2 的多个流共享一个 TCP 连接。TCP 提供的是有序字节流,当某个 TCP 报文段丢失时,即使后续报文已经到达,TCP 也通常要等待缺失数据重传并恢复顺序后,才会继续向 HTTP/2 交付后续字节。
因此,一个 TCP 丢包可能暂时阻塞同一连接中的多个 HTTP/2 流。这是 HTTP/2 没有彻底解决的 TCP 层队头阻塞。HTTP/1.1 使用多个连接时,可以把影响限制在某一个连接中,但会增加连接、TLS 和拥塞控制开销。
RTO(Retransmission Timeout)是重传超时时间。TCP 会根据连接的 RTT 和波动情况动态计算 RTO;TCP ACK 通常表示接收方希望收到的下一个字节序号,而不是简单表示“下一组数据包的序号”。


TCP 已经部署在大量操作系统、网络设备和中间盒中,不能轻易改变其基本的有序字节流语义。但 TCP 仍然可以通过选项和拥塞控制算法持续演进,HTTP/3 则选择在 UDP 之上重新实现一套适合多路复用的可靠传输协议 QUIC。
3. 并发流带来的资源压力
HTTP/2 可以在一个连接中快速创建多个流。如果服务端、代理或应用没有设置合适的并发流限制、队列和流量控制,大量请求可能在短时间内到达,造成 CPU、内存、连接级窗口和后端资源的瞬时压力。
这不是“多路复用一定导致 QPS 暴增”,而是并发请求的调度和资源管理需要更加谨慎。服务器可以通过 SETTINGS_MAX_CONCURRENT_STREAMS、连接级流量控制、应用层限流和队列等方式进行控制。
4. 请求超时并非 HTTP/2 固有问题
多个流同时传输时,网络带宽和服务器资源需要在这些流之间共享。如果请求数量过多、后端处理慢、连接级流控窗口过小或应用层排队不合理,就可能出现响应超时。
因此,HTTP/2 并不是“多路复用容易超时”,而是多路复用改变了请求并发模型,服务端需要配套设置超时、限流、队列和取消机制。超时策略还应在响应失去价值后及时取消对应的流,避免继续浪费资源。
五、HTTP/3 与 QUIC
1. HTTP/3 简介
HTTP/3 是将 HTTP 语义运行在 QUIC 之上的协议。QUIC 使用 UDP 作为底层数据报承载,但在 UDP 之上实现了可靠传输、拥塞控制、流量控制、加密握手和多路复用。
HTTP/3 已经完成标准化,主要规范是 RFC 9114;QUIC 的传输规范是 RFC 9000。HTTP/3 并不是简单地把 HTTP/2 的帧放进 UDP,而是使用 QUIC 的流、帧和 TLS 1.3 机制重新组织传输。

QUIC 主要解决的是 TCP 连接级队头阻塞和连接迁移问题,但并不保证所有网络环境下都比 HTTP/2 快。UDP 可能受到网络设备限速、丢包和部署策略影响,最终性能仍取决于具体网络和实现。
2. QUIC 的主要特性
2.1 在 UDP 之上提供可靠传输
UDP 本身不提供可靠性、连接状态、拥塞控制和有序字节流,但 QUIC 在 UDP 之上补充了这些能力。QUIC 流数据可以进行确认、丢包检测和重传,连接还具有流量控制和拥塞控制。
QUIC 并不保证数据在任何故障条件下“一定能够抵达”。如果连接断开、对端不可用或重传次数耗尽,应用程序仍会收到失败结果。
2.2 Packet Number、ACK 与流偏移
QUIC 使用 Packet Number 标识数据包,并为 Initial、Handshake、Application Data 等阶段维护不同的 Packet Number Space。Packet Number 主要用于 ACK 和丢包检测,不是 TCP 序列号的简单替代。
QUIC 流数据的顺序由每个 Stream 内的偏移量维护。QUIC 丢包恢复时通常重新发送需要恢复的帧,并将它们放入具有新 Packet Number 的数据包中,而不是简单重传完全相同的 UDP 数据包。
QUIC 的 ACK 可以确认多个数据包范围。一个数据包被确认后,发送方不会再把同一个 Packet Number 当作未确认数据包,但这与应用程序已经处理完数据并不是完全相同的概念。
2.3 可演进的拥塞控制和流量控制
QUIC 将传输协议实现放在用户态或更容易升级的协议栈中,算法可以更灵活地演进。具体实现可以选择不同的拥塞控制算法,但仍然需要遵守 QUIC 的拥塞控制和公平性要求。
QUIC 同时提供:
- 连接级流量控制;
- Stream 级流量控制;
- ACK 和丢包检测;
- 拥塞控制;
- 连接关闭和错误处理。
早期 QUIC 研究曾讨论过 FEC(前向纠错),但 QUIC v1 的核心可靠性主要依靠 ACK、丢包检测和重传,不能把 FEC 作为 QUIC 的普遍内置功能。
2.4 快速握手与 0-RTT
QUIC 将 TLS 1.3 集成到连接建立过程中。新的 QUIC 连接通常需要约 1-RTT 完成握手;如果客户端拥有之前会话的恢复信息,则可能使用 0-RTT 发送早期应用数据。
0-RTT 不是首次连接都能使用,也不代表完整连接已经完成。早期数据发送后,TLS 和 QUIC 握手仍需要继续完成。0-RTT 数据具有重放风险,并且不具备完整的前向保密性,因此只适合幂等、可安全重复执行的请求,不适合直接承载支付、转账等不可重复操作。
TLS 1.3 的 1-RTT 数据通常具有前向保密性;0-RTT 数据使用恢复会话的 PSK 相关密钥,在密钥泄露时可能使攻击者解密之前捕获的 0-RTT 数据。服务器还应采取票据轮换、重放检测和请求限制等措施。
2.5 基于流的多路复用
QUIC 允许同一连接包含多个相互独立的逻辑流。一个流中的数据丢失时,只会阻塞该流中需要按序交付的数据,其他流仍可以继续处理已收到的数据,从而避免 TCP 连接级队头阻塞。
但这并不意味着队头阻塞被“彻底解决”:
- 单个流内部仍然需要按序交付;
- 连接级流量控制和拥塞控制仍会影响所有流;
- HTTP/3 使用 QPACK 压缩首部时,某些动态表依赖也可能产生等待;
- 服务器和客户端的调度、CPU、内存及带宽仍然是共享资源。

2.6 连接迁移
传统 TCP 连接通常由客户端 IP、客户端端口、服务器 IP 和服务器端口组成的四元组识别。网络切换或 NAT 重绑定后,四元组可能发生变化,TCP 通常需要重新建立连接。
QUIC 使用 Connection ID 辅助识别连接。Connection ID 由连接端点发放和管理,长度可变,并不是固定的 64 位。只要满足握手已确认、路径验证通过以及其他迁移条件,客户端在切换网络或地址后可以继续使用同一个 QUIC 连接,而不必重新建立完整连接。
连接迁移并不是只要 Connection ID 不变就一定成功。QUIC 需要对新路径进行验证,服务器也需要遵守对新地址发送数据的限制。QUIC 的密钥上下文可以在迁移后继续使用,但仍可能发生密钥更新和路径相关的拥塞控制调整。
六、HTTP/2 与 HTTP/3 的对比
| 特性 | HTTP/1.1 | HTTP/2 | HTTP/3 |
|---|---|---|---|
| 传输格式 | 文本报文 | 二进制帧 | HTTP/3 帧运行在 QUIC 流上 |
| 底层传输 | TCP | TCP | UDP + QUIC |
| 首部压缩 | 无通用动态压缩 | HPACK | QPACK |
| 多路复用 | 依赖多个连接或管道化 | 同一 TCP 连接的多个流 | QUIC 连接的多个独立流 |
| TCP 连接级队头阻塞 | 不适用/每连接独立 | 存在 | 由 QUIC 避免 |
| 加密 | 可使用 TLS | 浏览器通常使用 TLS | QUIC 强制集成 TLS 1.3 |
| 服务器推送 | 无标准推送流 | 规范支持,但浏览器实际使用很少 | 规范支持,但实际使用同样有限 |
| 连接迁移 | 通常需要重新连接 | TCP 本身不支持 | QUIC 支持路径验证后的迁移 |
七、总结
- HTTP/1.1 的主要性能问题包括同一连接上的请求排队、首部重复和连接建立开销;域名分片、雪碧图、资源内联等旧优化需要结合实际场景使用。
- HTTP/2 保留了 HTTP 的主要语义,但使用二进制分帧、HPACK 和多路复用提高传输效率。它通常可以减少 HTTP 层队头阻塞,但仍受到 TCP 连接级队头阻塞影响。
- HTTP/2 的 Server Push 仍存在于规范中,但已经不是主流浏览器普遍使用的性能手段。
- HTTP/3 将 HTTP 运行在 QUIC 之上,使用 QPACK、独立流、TLS 1.3、0-RTT 和连接迁移等能力,主要解决 TCP 连接级队头阻塞和网络切换问题。
- HTTP/2 和 HTTP/3 都不保证一定更快,最终效果取决于网络、资源、服务器、客户端、缓存和部署方式。
延伸阅读
- HTTP/2.0 原理详细分析
- HPACK:HTTP/2 里的首部压缩
- QPACK:HTTP/3 的首部压缩
- DH 算法
- 前向安全(Forward Secrecy)
- TLS 1.3 对比 TLS 1.2
- Caddy Web 服务器 QUIC 部署
- 关于 QUIC 的各种尝试
- 使用 QUIC 协议实现实时视频直播
- 解密 HTTP/2 与 HTTP/3 的新特性
- Web 通信协议:SPDY 和 QUIC
- 如何看待 HTTP/3?