1.基础概念

HTTP/2 于 2015 年正式发布(RFC 7540),基于 Google 的 SPDY 协议演进而来。它没有改变 HTTP 的语义(方法、状态码、头部字段含义不变),而是彻底重构了数据传输的方式,从文本协议升级为二进制协议。

尽管HTTP/1.1可以使用长连接来稳定输出请求,并且采用管道化技术,发送多个请求处理,但是仍然也有问题,管道话处理仅仅只能顺序化处理多个请求,需要开多个连接才能真正的并发,并且不会压缩头部和数据,会浪费资源

![[Pasted image 20260328201459.png]]

HTTP/2在应用层和传输层之间增加了二进制分帧,突破了HTTP/1.1性能限制,改进传输性能,实现低延迟和高吞吐量。同时用二进制分帧,实现了多个请求合并为单个请求的功能。采用流式输入输出,能有更高的吞吐率

1.1 二进制分帧

当出现多个请求,且请求类型一致时,我们可以共用单个请求头,然后将数据放到数据帧中,如下。
![[Pasted image 20260309235110.png]]
那么HTTP/2.0的数据 = HEADERS帧 + DATA 帧。数据会被压缩到TCP报文段中的数据里面,这样一次TCP收发可以发送多个请求和响应。

二进制帧实现的更重要功能则是多路复用:
多路复用允许同时通过单一的HTTP/2连接发起多重的请求-响应消息,实现多流并行而并不依赖多个TCP连接,HTTP/2把HTTP协议通信的基本单位缩小为一个一个的帧,这些帧对应着逻辑流中的消息,并行地在同一个TCP连接上双向交换消息。

HTTP/2基于二进制分帧层,HTTP/2可以在共享TCP连接的基础上同时发送请求和响应。HTTP消息被分解为独立的帧,而不破坏消息本身的语义交错发出去,在另一端根据流标识符和首部将他们重新组装起来。通过多路复用技术,可以避免HTTP旧版本的消息头阻塞问题,极大提高传输性能。

1.2 多路复用

在二进制分帧的基础上,HTTP/2.0采用多路复用来发送多个请求。
![[Pasted image 20260328201621.png]]
HTTP/2 最核心的特性。一条 TCP 连接上可以同时跑多个流(Stream),每个流承载一对请求/响应,帧可以交错发送,彻底消除了 HTTP/1.1 的应用层队头阻塞。

流(Stream)是 HTTP/2 的核心概念:每个流有唯一整数 ID(客户端发起用奇数,服务器发起用偶数),携带一对完整的请求/响应。不同流的帧可以任意交错,接收端按流 ID 重新组装,互不干扰。

1.3 头部压缩

采用字典表,将所有的符号映射到索引上。
![[Pasted image 20260328201849.png]]

HTTP 是无状态协议,每次请求都要重复发送大量相同的头部字段,如 User-AgentCookieAccept-Encoding 等,有时头部比正文还大。HTTP/2 用 HPACK 算法专门解决这个问题。

HPACK 有两张表:静态表内置 61 条常用头部,动态表在会话期间随请求累积。发送端和接收端各维护一份完全相同的表,传输时只需发索引号,重复头部几乎不占带宽。

1.4 服务器推送

HTTP/2 允许服务器在客户端请求某个资源时,主动将依赖资源一并推送,无需等客户端解析 HTML 后再发起子请求。
![[Pasted image 20260328201935.png]]
服务器先发 PUSH_PROMISE 帧告知客户端将要推送哪些资源,客户端若已有缓存可发 RST_STREAM 拒绝,避免重复传输。实践中因缓存感知困难,Server Push 在 HTTP/3 中已被废弃,被更精准的 Early Hints(103)替代。

其问题也很简单:如果用户只是不小心点击到了网页,网页一下就推送很多内容,导致网页多了很多不应该由的缓存。

1.5 优先级和流控制

HTTP/2 允许为每个流设置权重(1–256)和依赖关系,构成优先级树,指导服务器资源分配顺序。同时,流和连接级别都有独立的流量控制窗口(基于信用机制),防止快速发送方淹没慢速接收方。

2.问题

2.1 TCP层级的队头阻塞

这是 HTTP/2 最大的致命伤。 虽然 HTTP/2 的多路复用解决了应用层(HTTP 层)的队头阻塞(把多个请求(响应)塞到同一个TCP连接里面),但它把问题转移到了传输层(TCP 层)。

  • 问题表现: HTTP/2 的所有流(Stream)都跑在同一条 TCP 连接上。TCP 是保证有序可靠传输的,如果网络中发生了丢包,TCP 必须等待丢失的包被重新传输。
  • 后果: 这会导致整个 TCP 连接被暂停,所有正在该连接上复用的 HTTP/2 流(即使它们的数据没有丢失)都会被卡住,直到丢包恢复。在丢包率较高的弱网环境下(如移动网络),HTTP/2 的表现甚至可能不如开了多个连接的 HTTP/1.1。

2.2 握手延迟高(连接建立成本高)

HTTP/2 强依赖于 TCP 和 TLS(HTTPS 是事实标准)。建立一次完整的 HTTP/2 连接需要消耗大量的 RTT(往返时延):

  • TCP 三次握手需要消耗 1 个 RTT。
  • TLS 握手(通常是 TLS 1.2 或 1.3)又需要消耗 1 到 2 个 RTT。
  • 后果: 尽管多路复用可以复用连接,但首次建立连接时的延迟依然很高。对于生命周期短、需要快速响应的请求,建立连接的成本显得非常昂贵

2.3 网络切换导致连接断开(缺乏连接迁移能力)

TCP 连接是通过四元组(源 IP、源端口、目标 IP、目标端口)来标识的。

  • 问题表现: 当移动设备在不同网络之间切换时(例如从 Wi-Fi 切换到 5G 蜂窝网络),设备的 IP 地址会发生变化。
  • 后果: 底层的 TCP 连接会直接断开。由于 HTTP/2 所有的请求都复用这一条连接,这会导致当前所有的并发请求瞬间全部失败,必须重新经历耗时的 TCP 和 TLS 握手。

2.4 优先级模型设计过于复杂且难以实现

正如你笔记中提到的优先级和流控制,HTTP/2 允许通过复杂的“依赖树”和“权重”来控制优先级。

  • 实际情况: 这个设计在理论上很完美,但在实践中过于复杂。很多服务器和浏览器并没有完全按照规范正确实现,或者实现得非常低效,导致这个特性在实际网络中并没有发挥出预期的效果。(这一点在后来的 HTTP/3 中被大幅简化了)。

2.5 协议复杂性带来的资源消耗

HTTP/2 从简单的文本协议变成了复杂的二进制状态协议,增加了服务器和客户端的性能开销:

  • HPACK 动态表: 为了压缩头部,通信双方必须在整个连接的生命周期内维护相同的动态字典表。对于拥有海量并发连接的服务器来说,这会消耗巨大的内存。
  • 状态管理: 服务器需要管理数以百计的流(Stream)、处理帧的乱序组装、计算优先级树(Priority Tree)以及维护流控制窗口,导致 CPU 计算压力显著增加。

2.5 单一连接带来的安全风险

由于所有流量都集中在一个 TCP 连接上,这引发了新的攻击面。例如 2023 年爆发的 HTTP/2 Rapid Reset 漏洞 (CVE-2023-44487)。攻击者通过疯狂发送请求帧然后立即发送 RST_STREAM 帧(取消请求),绕过服务器的并发流限制,迅速耗尽服务器的 CPU 和内存,造成了互联网历史上规模最大的 DDoS 攻击之一。

添加新评论