HTTP/2 帧类型及其作用详解
字数 4188 2025-12-11 04:24:58

HTTP/2 帧类型及其作用详解

一、描述与背景

HTTP/2是HTTP协议的重大修订版本,其核心改进之一是将数据拆分为更小的帧(Frame) ,并通过一个TCP连接内的多路复用流进行传输。帧是HTTP/2二进制格式的最小通信单位,每种帧类型承担不同的作用,共同实现了高效、灵活的通信。理解帧类型及其交互是掌握HTTP/2性能优势(如多路复用、头部压缩、服务端推送)的基础。

二、核心概念与术语

在详解帧之前,需明确三个层次概念:

  1. 帧(Frame):HTTP/2通信的最小二进制单元,每个帧都包含一个帧头(Frame Header) 和不同类型的帧载荷(Frame Payload)
  2. 流(Stream):一个独立的双向字节流,用于承载一次请求及其响应。一个连接可包含多个并发流。
  3. 消息(Message):一个完整的请求或响应,由一个或多个HEADERS帧和零个或多个DATA帧组成。

帧头是每个帧的公共前缀,固定9字节,包含:

  • 长度(Length):3字节,表示帧载荷的长度(不包括9字节帧头)。
  • 类型(Type):1字节,标识帧类型(如0x0表示DATA帧)。
  • 标志(Flags):1字节,特定于帧类型的布尔标志,如END_STREAM、END_HEADERS等。
  • R(保留位):1位,必须为0。
  • 流标识符(Stream Identifier):31位,标识该帧所属的流。流ID为0的帧属于整个连接,而非特定流

三、帧类型详解

HTTP/2定义了10种标准帧类型,我们按功能分类讲解:

第一类:数据与头部帧(承载请求/响应内容)

1. DATA帧(类型=0x0)

  • 作用:承载请求或响应的主体数据(如HTML内容、JSON数据)。
  • 帧载荷:纯字节数据块。
  • 关键标志
    • END_STREAM(0x1):设置为1表示当前帧是该流的最后一帧。例如,一个GET响应的DATA帧若设置了END_STREAM,表示响应体结束且流关闭。
    • PADDED(0x8):用于在帧载荷前添加填充字节以实现流量整形或混淆长度。
  • 注意:DATA帧必须关联到一个已打开的流。

2. HEADERS帧(类型=0x1)

  • 作用:打开一个流(对于请求或响应),并携带HTTP头部字段(压缩后)。
  • 帧载荷:包含:
    • (可选)填充长度(如果设置了PADDED标志)。
    • (可选)流依赖和权重(如果设置了PRIORITY标志),用于优先级排序。
    • 使用HPACK压缩后的头部块片段。
  • 关键标志
    • END_STREAM(0x1):设置为1表示该帧后没有DATA帧(例如,一个没有请求体的GET请求的HEADERS帧会设置此标志)。
    • END_HEADERS(0x4):设置为1表示这是该消息的最后一个头部块片段。一个完整的头部可能被拆分成多个HEADERS帧(或HEADERS + CONTINUATION帧),最后一个片段需设置此标志。
    • PADDED(0x8):同DATA帧。
    • PRIORITY(0x20):表示帧载荷中包含优先级信息。

第二类:流控制与管理帧

3. PRIORITY帧(类型=0x2)

  • 作用:指定或更新一个流的优先级,帮助接收端在资源有限时决定流的处理顺序。
  • 帧载荷
    • 流依赖(Stream Dependency):31位,指定当前流所依赖的流ID。
    • 权重(Weight):1字节,取值1~256,相对于其他兄弟流的权重。
  • 工作模式:依赖关系构成一棵“优先级树”。权重决定兄弟流间分配资源的比例。

4. RST_STREAM帧(类型=0x3)

  • 作用:立即终止一个流。用于在出现错误(如流被取消、协议错误)时,告知对方无需继续处理该流。
  • 帧载荷:一个32位错误码(如NO_ERROR(0x0)PROTOCOL_ERROR(0x1)CANCEL(0x8)等)。
  • 注意:发送后,该流即进入“关闭”状态。

5. SETTINGS帧(类型=0x4)

  • 作用连接级配置参数交换,是连接建立后(或运行中)双方沟通“游戏规则”的机制。
  • 帧载荷:由零个或多个参数项组成,每个参数项包含一个16位的标识符和一个32位的
  • 关键设置项
    • SETTINGS_HEADER_TABLE_SIZE (0x1):通知对端用于HPACK头部压缩的最大表大小。
    • SETTINGS_ENABLE_PUSH (0x2):值为0表示禁用服务端推送(Server Push)。
    • SETTINGS_MAX_CONCURRENT_STREAMS (0x3):发送端允许接收端创建的最大并发流数。
    • SETTINGS_INITIAL_WINDOW_SIZE (0x4):流的初始流量控制窗口大小(字节)。
    • SETTINGS_MAX_FRAME_SIZE (0x5):单个帧载荷的最大允许字节数。
    • SETTINGS_MAX_HEADER_LIST_SIZE (0x6):发送端愿意接收的未压缩头部列表的最大大小。
  • 标志
    • ACK (0x1):当接收方收到并应用SETTINGS帧后,需回复一个空载荷(无参数项)且设置了ACK标志的SETTINGS帧作为确认。

6. WINDOW_UPDATE帧(类型=0x8)

  • 作用流量控制的核心。用于更新连接级流级的发送窗口大小,通知对端可以发送更多数据。
  • 帧载荷:一个31位的窗口大小增量(Window Size Increment)。注意这是“增量”,不是绝对大小。
  • 流ID为0:更新整个连接的流量控制窗口(控制所有流总和)。
  • 流ID非0:更新该特定流的流量控制窗口。
  • 初始窗口大小:由SETTINGS帧的SETTINGS_INITIAL_WINDOW_SIZE设定。当发送方数据超过窗口时,必须暂停发送,直到收到对方的WINDOW_UPDATE帧来扩大窗口。

7. GOAWAY帧(类型=0x7)

  • 作用连接级优雅终止连接或发出严重错误信号。发送方告知接收方“停止为某些流创建新流,但处理完已建立的流再关闭”。
  • 帧载荷
    • 最后流ID(Last-Stream-ID):31位,发送方已处理或正在处理的最后一个有效流的ID。接收方应创建大于此ID的新流。
    • 错误码:32位,解释连接关闭的原因。
    • 调试数据:可选,用于附加调试信息。
  • 应用场景:服务器优雅关闭、协议严重错误。

第三类:服务端推送相关帧

8. PUSH_PROMISE帧(类型=0x5)

  • 作用服务端推送的发起帧。服务器在响应客户端原始请求时,使用此帧预先告知客户端“我打算推送一个额外资源给你”。
  • 帧载荷
    • (可选)填充长度。
    • 承诺流ID(Promised Stream ID):31位,服务器为将要推送的资源预留的新流的ID(必须是偶数,且大于关联的原始流的ID)。
    • 使用HPACK压缩后的、将要推送资源的请求头部块片段。
  • 关键标志
    • END_HEADERS:同HEADERS帧。
    • PADDED:同DATA帧。
  • 后续:服务器随后会使用这个“承诺流ID”发送一个HEADERS帧(模拟请求)和DATA帧(推送资源内容)。

第四类:辅助与特殊用途帧

9. PING帧(类型=0x6)

  • 作用:测量连接的空闲时间(RTT)和检测连接是否存活。
  • 帧载荷:8字节不透明数据(通常由发送方填充唯一值)。
  • 标志ACK (0x1)。接收方收到PING帧后,必须回复一个载荷相同且设置了ACK标志的PING帧。
  • 注意:PING帧的流ID必须为0,属于连接控制帧。

10. CONTINUATION帧(类型=0x9)

  • 作用:当HEADERS或PUSH_PROMISE帧的头部块太大,无法放入单个帧时,用于延续头部块片段。
  • 帧载荷:纯粹的HPACK头部块后续片段。
  • 关键标志:必须设置END_HEADERS标志,表示这是该头部块的最后一个片段。
  • 规则:CONTINUATION帧必须紧跟在未设置END_HEADERS标志的HEADERS或PUSH_PROMISE帧之后,且流ID必须与前面的帧相同。

四、帧的交互与典型通信流程

以一个简单的GET请求为例,说明帧的交互:

  1. 连接建立:TCP连接建立后,客户端发送一个SETTINGS帧(通常包含一些初始参数)。
  2. 开启流:客户端在新流(如流ID=1)上发送一个HEADERS帧,携带压缩后的请求头(如:method: GET, :path: /index.html),并设置END_STREAM=1(表示无请求体,请求结束)。
  3. 服务端响应:服务器在同一个流(ID=1)上先发送一个HEADERS帧,携带响应状态(如:status: 200),通常接着发送一个或多个DATA帧承载响应体。
  4. 响应结束:最后一个DATA帧设置END_STREAM=1标志,表示响应结束,该流关闭。
  5. 流量控制:如果接收方处理速度慢,其WINDOW_UPDATE帧会控制发送方的数据发送速率。
  6. 连接管理:如果服务器需要重启,它可以发送一个GOAWAY帧,指定已处理的最后一个流ID,让客户端停止创建新请求,但处理完已接收的流后关闭连接。

五、总结与核心价值

HTTP/2帧类型的设计实现了协议核心特性的解耦和精细化控制:

  • 多路复用:通过流ID在单个连接上交织传输不同流的帧。
  • 优先级:通过PRIORITY帧和流依赖关系实现资源调度优化。
  • 流量控制:通过WINDOW_UPDATE帧实现连接级和流级的精细流量控制。
  • 头部压缩HEADERSPUSH_PROMISECONTINUATION帧承载HPACK压缩的头部。
  • 服务端推送:通过PUSH_PROMISE帧发起。
  • 健壮性:通过RST_STREAMGOAWAYPING等帧实现错误处理、连接管理和健康检查。

理解每种帧的角色及其交互,是深入诊断HTTP/2性能问题、理解高级特性(如优先级、流量控制)以及进行协议级优化的关键。

HTTP/2 帧类型及其作用详解 一、描述与背景 HTTP/2是HTTP协议的重大修订版本,其核心改进之一是将数据拆分为更小的 帧(Frame) ,并通过一个TCP连接内的多路复用流进行传输。帧是HTTP/2二进制格式的最小通信单位,每种帧类型承担不同的作用,共同实现了高效、灵活的通信。理解帧类型及其交互是掌握HTTP/2性能优势(如多路复用、头部压缩、服务端推送)的基础。 二、核心概念与术语 在详解帧之前,需明确三个层次概念: 帧(Frame) :HTTP/2通信的最小二进制单元,每个帧都包含一个 帧头(Frame Header) 和不同类型的 帧载荷(Frame Payload) 。 流(Stream) :一个独立的双向字节流,用于承载一次请求及其响应。一个连接可包含多个并发流。 消息(Message) :一个完整的请求或响应,由一个或多个 HEADERS帧 和零个或多个 DATA帧 组成。 帧头 是每个帧的公共前缀,固定9字节,包含: 长度(Length) :3字节,表示帧载荷的长度(不包括9字节帧头)。 类型(Type) :1字节,标识帧类型(如0x0表示DATA帧)。 标志(Flags) :1字节,特定于帧类型的布尔标志,如END_ STREAM、END_ HEADERS等。 R(保留位) :1位,必须为0。 流标识符(Stream Identifier) :31位,标识该帧所属的流。 流ID为0的帧属于整个连接,而非特定流 。 三、帧类型详解 HTTP/2定义了10种标准帧类型,我们按功能分类讲解: 第一类:数据与头部帧(承载请求/响应内容) 1. DATA帧(类型=0x0) 作用 :承载请求或响应的主体数据(如HTML内容、JSON数据)。 帧载荷 :纯字节数据块。 关键标志 : END_STREAM (0x1):设置为1表示当前帧是该流的最后一帧。例如,一个GET响应的DATA帧若设置了 END_STREAM ,表示响应体结束且流关闭。 PADDED (0x8):用于在帧载荷前添加填充字节以实现流量整形或混淆长度。 注意 :DATA帧必须关联到一个已打开的流。 2. HEADERS帧(类型=0x1) 作用 :打开一个流(对于请求或响应),并携带HTTP头部字段(压缩后)。 帧载荷 :包含: (可选)填充长度(如果设置了 PADDED 标志)。 (可选)流依赖和权重(如果设置了 PRIORITY 标志),用于优先级排序。 使用HPACK压缩后的头部块片段。 关键标志 : END_STREAM (0x1):设置为1表示该帧后没有DATA帧(例如,一个没有请求体的GET请求的HEADERS帧会设置此标志)。 END_HEADERS (0x4):设置为1表示这是该消息的最后一个头部块片段。一个完整的头部可能被拆分成多个HEADERS帧(或HEADERS + CONTINUATION帧),最后一个片段需设置此标志。 PADDED (0x8):同DATA帧。 PRIORITY (0x20):表示帧载荷中包含优先级信息。 第二类:流控制与管理帧 3. PRIORITY帧(类型=0x2) 作用 :指定或更新一个流的优先级,帮助接收端在资源有限时决定流的处理顺序。 帧载荷 : 流依赖(Stream Dependency) :31位,指定当前流所依赖的流ID。 权重(Weight) :1字节,取值1~256,相对于其他兄弟流的权重。 工作模式 :依赖关系构成一棵“优先级树”。权重决定兄弟流间分配资源的比例。 4. RST_ STREAM帧(类型=0x3) 作用 :立即终止一个流。用于在出现错误(如流被取消、协议错误)时,告知对方无需继续处理该流。 帧载荷 :一个32位错误码(如 NO_ERROR(0x0) 、 PROTOCOL_ERROR(0x1) 、 CANCEL(0x8) 等)。 注意 :发送后,该流即进入“关闭”状态。 5. SETTINGS帧(类型=0x4) 作用 : 连接级 配置参数交换,是连接建立后(或运行中)双方沟通“游戏规则”的机制。 帧载荷 :由零个或多个参数项组成,每个参数项包含一个16位的 标识符 和一个32位的 值 。 关键设置项 : SETTINGS_HEADER_TABLE_SIZE (0x1) :通知对端用于HPACK头部压缩的最大表大小。 SETTINGS_ENABLE_PUSH (0x2) :值为0表示禁用服务端推送(Server Push)。 SETTINGS_MAX_CONCURRENT_STREAMS (0x3) :发送端允许接收端创建的最大并发流数。 SETTINGS_INITIAL_WINDOW_SIZE (0x4) :流的初始流量控制窗口大小(字节)。 SETTINGS_MAX_FRAME_SIZE (0x5) :单个帧载荷的最大允许字节数。 SETTINGS_MAX_HEADER_LIST_SIZE (0x6) :发送端愿意接收的未压缩头部列表的最大大小。 标志 : ACK (0x1) :当接收方收到并应用SETTINGS帧后,需回复一个空载荷(无参数项)且设置了 ACK 标志的SETTINGS帧作为确认。 6. WINDOW_ UPDATE帧(类型=0x8) 作用 : 流量控制 的核心。用于更新 连接级 或 流级 的发送窗口大小,通知对端可以发送更多数据。 帧载荷 :一个31位的 窗口大小增量 (Window Size Increment)。注意这是“增量”,不是绝对大小。 流ID为0 :更新整个连接的流量控制窗口(控制所有流总和)。 流ID非0 :更新该特定流的流量控制窗口。 初始窗口大小 :由SETTINGS帧的 SETTINGS_INITIAL_WINDOW_SIZE 设定。当发送方数据超过窗口时,必须暂停发送,直到收到对方的WINDOW_ UPDATE帧来扩大窗口。 7. GOAWAY帧(类型=0x7) 作用 : 连接级 优雅终止连接或发出严重错误信号。发送方告知接收方“停止为某些流创建新流,但处理完已建立的流再关闭”。 帧载荷 : 最后流ID(Last-Stream-ID) :31位,发送方已处理或正在处理的最后一个有效流的ID。接收方应创建大于此ID的新流。 错误码 :32位,解释连接关闭的原因。 调试数据 :可选,用于附加调试信息。 应用场景 :服务器优雅关闭、协议严重错误。 第三类:服务端推送相关帧 8. PUSH_ PROMISE帧(类型=0x5) 作用 : 服务端推送 的发起帧。服务器在响应客户端原始请求时,使用此帧预先告知客户端“我打算推送一个额外资源给你”。 帧载荷 : (可选)填充长度。 承诺流ID(Promised Stream ID) :31位,服务器为将要推送的资源预留的新流的ID(必须是偶数,且大于关联的原始流的ID)。 使用HPACK压缩后的、将要推送资源的请求头部块片段。 关键标志 : END_HEADERS :同HEADERS帧。 PADDED :同DATA帧。 后续 :服务器随后会使用这个“承诺流ID”发送一个HEADERS帧(模拟请求)和DATA帧(推送资源内容)。 第四类:辅助与特殊用途帧 9. PING帧(类型=0x6) 作用 :测量连接的空闲时间(RTT)和检测连接是否存活。 帧载荷 :8字节不透明数据(通常由发送方填充唯一值)。 标志 : ACK (0x1) 。接收方收到PING帧后,必须回复一个载荷相同且设置了 ACK 标志的PING帧。 注意 :PING帧的流ID必须为0,属于连接控制帧。 10. CONTINUATION帧(类型=0x9) 作用 :当HEADERS或PUSH_ PROMISE帧的头部块太大,无法放入单个帧时,用于延续头部块片段。 帧载荷 :纯粹的HPACK头部块后续片段。 关键标志 :必须设置 END_HEADERS 标志,表示这是该头部块的最后一个片段。 规则 :CONTINUATION帧必须紧跟在未设置 END_HEADERS 标志的HEADERS或PUSH_ PROMISE帧之后,且流ID必须与前面的帧相同。 四、帧的交互与典型通信流程 以一个简单的GET请求为例,说明帧的交互: 连接建立 :TCP连接建立后,客户端发送一个 SETTINGS 帧(通常包含一些初始参数)。 开启流 :客户端在新流(如流ID=1)上发送一个 HEADERS 帧,携带压缩后的请求头(如 :method: GET, :path: /index.html ),并设置 END_STREAM=1 (表示无请求体,请求结束)。 服务端响应 :服务器在同一个流(ID=1)上先发送一个 HEADERS 帧,携带响应状态(如 :status: 200 ),通常接着发送一个或多个 DATA 帧承载响应体。 响应结束 :最后一个 DATA 帧设置 END_STREAM=1 标志,表示响应结束,该流关闭。 流量控制 :如果接收方处理速度慢,其 WINDOW_UPDATE 帧会控制发送方的数据发送速率。 连接管理 :如果服务器需要重启,它可以发送一个 GOAWAY 帧,指定已处理的最后一个流ID,让客户端停止创建新请求,但处理完已接收的流后关闭连接。 五、总结与核心价值 HTTP/2帧类型的设计实现了协议核心特性的解耦和精细化控制: 多路复用 :通过流ID在单个连接上交织传输不同流的帧。 优先级 :通过 PRIORITY 帧和流依赖关系实现资源调度优化。 流量控制 :通过 WINDOW_UPDATE 帧实现连接级和流级的精细流量控制。 头部压缩 : HEADERS 、 PUSH_PROMISE 、 CONTINUATION 帧承载HPACK压缩的头部。 服务端推送 :通过 PUSH_PROMISE 帧发起。 健壮性 :通过 RST_STREAM 、 GOAWAY 、 PING 等帧实现错误处理、连接管理和健康检查。 理解每种帧的角色及其交互,是深入诊断HTTP/2性能问题、理解高级特性(如优先级、流量控制)以及进行协议级优化的关键。