6. 帧定义
本规范定义了若干帧类型, 每种类型由唯一的 8 位类型码标识. 每种帧类型在建立和管理整个连接或单个流时都有不同用途.
特定帧类型的传输可能改变连接状态. 如果端点无法维护同步的连接状态视图, 连接内的成功通信将不再可能. 因此, 端点必须共同理解使用任意给定帧如何影响状态.
6.1. DATA
DATA 帧 (type=0x00) 传送与流关联的任意可变长度八位组序列. 例如, 一个或多个 DATA 帧用于承载 HTTP 请求或响应消息内容.
DATA 帧 MAY 也包含填充. 可以向 DATA 帧添加填充以掩盖消息大小. 填充是一项安全特性; 见 Section 10.7.
DATA Frame {
Length (24),
Type (8) = 0x00,
Unused Flags (4),
PADDED Flag (1),
Unused Flags (2),
END_STREAM Flag (1),
Reserved (1),
Stream Identifier (31),
[Pad Length (8)],
Data (..),
Padding (..2040),
}
Figure 3: DATA Frame Format
Length、Type、Unused Flag(s)、Reserved 和 Stream Identifier 字段见 Section 4. DATA 帧包含以下附加字段:
Pad Length: 一个 8 位字段, 以八位组为单位包含帧填充的长度. 该字段是条件字段, 仅在设置 PADDED 标志时出现.
Data: 应用数据. 数据量为扣除其他存在字段长度后的帧载荷剩余部分.
Padding: 不包含应用语义值的填充八位组. 发送时 Padding 八位组 MUST 设置为零. 接收方没有义务验证填充, 但 MAY 将非零填充视为 PROTOCOL_ERROR 类型的连接错误 (Section 5.4.1).
DATA 帧定义以下标志:
PADDED (0x08): 设置时, PADDED 标志表示 Pad Length 字段及其描述的任何填充均存在.
END_STREAM (0x01): 设置时, END_STREAM 标志表示该帧是端点将在所标识流上发送的最后一个帧. 设置此标志会使流进入某个 "half-closed" 状态或 "closed" 状态 (Section 5.1).
| Note: 在发送所有数据后得知流关闭的端点, 可以通过发送 Data 字段长度为零且
| 设置 END_STREAM 标志的 STREAM 帧来关闭流. 只有当端点不发送 trailers 时才
| 可能这样做, 因为在这种情况下 END_STREAM 标志会出现在 HEADERS 帧上; 见 Section 8.1.
DATA 帧 MUST 与流关联. 如果收到的 DATA 帧的 Stream Identifier 字段为 0x00, 接收者 MUST 以 PROTOCOL_ERROR 类型的连接错误 (Section 5.4.1) 响应.
DATA 帧受流量控制约束, 并且只能在流处于 "open" 或 "half-closed (remote)" 状态时发送. 整个 DATA 帧载荷都计入流量控制, 包括存在时的 Pad Length 和 Padding 字段. 如果收到的 DATA 帧所属流不处于 "open" 或 "half-closed (local)" 状态, 接收者 MUST 以 STREAM_CLOSED 类型的流错误 (Section 5.4.2) 响应.
填充八位组总数由 Pad Length 字段值确定. 如果填充长度等于或大于帧载荷长度, 接收者 MUST 将其视为 PROTOCOL_ERROR 类型的连接错误 (Section 5.4.1).
| Note: 通过包含值为零的 Pad Length 字段, 可以将帧大小增加一个八位组.
6.2. HEADERS
HEADERS 帧 (type=0x01) 用于打开流 (Section 5.1), 并额外携带字段块片段. 尽管名称如此, HEADERS 帧可以携带头部段或尾部段. HEADERS 帧可以在处于 "idle"、"reserved (local)"、"open" 或 "half-closed (remote)" 状态的流上发送.
HEADERS Frame {
Length (24),
Type (8) = 0x01,
Unused Flags (2),
PRIORITY Flag (1),
Unused Flag (1),
PADDED Flag (1),
END_HEADERS Flag (1),
Unused Flag (1),
END_STREAM Flag (1),
Reserved (1),
Stream Identifier (31),
[Pad Length (8)],
[Exclusive (1)],
[Stream Dependency (31)],
[Weight (8)],
Field Block Fragment (..),
Padding (..2040),
}
Figure 4: HEADERS Frame Format
Length、Type、Unused Flag(s)、Reserved 和 Stream Identifier 字段见 Section 4. HEADERS 帧载荷包含以下附加字段:
Pad Length: 一个 8 位字段, 以八位组为单位包含帧填充长度. 该字段仅在设置 PADDED 标志时出现.
Exclusive: 单比特标志. 该字段仅在设置 PRIORITY 标志时出现. HEADERS 帧中的优先级信号已废弃; 见 Section 5.3.2.
Stream Dependency: 一个 31 位流标识符. 该字段仅在设置 PRIORITY 标志时出现.
Weight: 一个无符号 8 位整数. 该字段仅在设置 PRIORITY 标志时出现.
Field Block Fragment: 字段块片段 (Section 4.3).
Padding: 不包含应用语义值的填充八位组. 发送时 Padding 八位组 MUST 设置为零. 接收方没有义务验证填充, 但 MAY 将非零填充视为 PROTOCOL_ERROR 类型的连接错误 (Section 5.4.1).
HEADERS 帧定义以下标志:
PRIORITY (0x20): 设置时, PRIORITY 标志表示 Exclusive、Stream Dependency 和 Weight 字段存在.
PADDED (0x08): 设置时, PADDED 标志表示 Pad Length 字段及其描述的任何填充均存在.
END_HEADERS (0x04): 设置时, END_HEADERS 标志表示该帧包含完整字段块 (Section 4.3), 且后面不会跟随任何 CONTINUATION 帧.
未设置 END_HEADERS 标志的 HEADERS 帧 MUST 后跟同一流上的 CONTINUATION 帧.
接收方 MUST 将收到任何其他类型帧或不同流上的帧视为 PROTOCOL_ERROR 类型的
连接错误 (Section 5.4.1).
END_STREAM (0x01): 设置时, END_STREAM 标志表示字段块 (Section 4.3) 是端点将在所标识流上发送的最后内容.
设置了 END_STREAM 标志的 HEADERS 帧表示流结束. 但是, 设置了 END_STREAM 标志的
HEADERS 帧后仍可跟随同一流上的 CONTINUATION 帧. 从逻辑上讲, CONTINUATION 帧是
HEADERS 帧的一部分.
HEADERS 帧的帧载荷包含字段块片段 (Section 4.3). 无法放入一个 HEADERS 帧的字段块会在 CONTINUATION 帧 (Section 6.10) 中继续.
HEADERS 帧 MUST 与流关联. 如果收到的 HEADERS 帧的 Stream Identifier 字段为 0x00, 接收者 MUST 以 PROTOCOL_ERROR 类型的连接错误 (Section 5.4.1) 响应.
HEADERS 帧按 Section 4.3 中的描述改变连接状态.
填充八位组总数由 Pad Length 字段值确定. 如果填充长度等于或大于帧载荷长度, 接收者 MUST 将其视为 PROTOCOL_ERROR 类型的连接错误 (Section 5.4.1).
| Note: 通过包含值为零的 Pad Length 字段, 可以将帧大小增加一个八位组.
6.3. PRIORITY
PRIORITY 帧 (type=0x02) 已废弃; 见 Section 5.3.2. PRIORITY 帧可以在任何流状态下发送, 包括 idle 或 closed 流.
PRIORITY Frame {
Length (24) = 0x05,
Type (8) = 0x02,
Unused Flags (8),
Reserved (1),
Stream Identifier (31),
Exclusive (1),
Stream Dependency (31),
Weight (8),
}
Figure 5: PRIORITY Frame Format
Length、Type、Unused Flag(s)、Reserved 和 Stream Identifier 字段见 Section 4. PRIORITY 帧的帧载荷包含以下附加字段:
Exclusive: 单比特标志.
Stream Dependency: 一个 31 位流标识符.
Weight: 一个无符号 8 位整数.
PRIORITY 帧不定义任何标志.
PRIORITY 帧始终标识一个流. 如果收到的 PRIORITY 帧的流标识符为 0x00, 接收者 MUST 以 PROTOCOL_ERROR 类型的连接错误 (Section 5.4.1) 响应.
发送或接收 PRIORITY 帧不会影响任何流的状态 (Section 5.1). PRIORITY 帧可以在任何状态的流上发送, 包括 "idle" 或 "closed". PRIORITY 帧不能在组成单个字段块 (Section 4.3) 的连续帧之间发送.
长度不是 5 个八位组的 PRIORITY 帧 MUST 被视为 FRAME_SIZE_ERROR 类型的流错误 (Section 5.4.2).
6.4. RST_STREAM
RST_STREAM 帧 (type=0x03) 允许立即终止流. RST_STREAM 被发送用于请求取消流, 或表示发生了错误条件.
RST_STREAM Frame {
Length (24) = 0x04,
Type (8) = 0x03,
Unused Flags (8),
Reserved (1),
Stream Identifier (31),
Error Code (32),
}
Figure 6: RST_STREAM Frame Format
Length、Type、Unused Flag(s)、Reserved 和 Stream Identifier 字段见 Section 4. 此外, RST_STREAM 帧包含一个无符号 32 位整数, 用于标识错误码 (Section 7). 错误码指示流为何终止.
RST_STREAM 帧不定义任何标志.
RST_STREAM 帧完全终止被引用的流, 并使其进入 "closed" 状态. 在流上收到 RST_STREAM 后, 接收方 MUST NOT 为该流发送其他帧, PRIORITY 除外. 但是, 发送 RST_STREAM 后, 发送端点 MUST 准备好接收并处理对等方可能已在 RST_STREAM 到达前发送到该流上的其他帧.
RST_STREAM 帧 MUST 与流关联. 如果收到的 RST_STREAM 帧的流标识符为 0x00, 接收者 MUST 将其视为 PROTOCOL_ERROR 类型的连接错误 (Section 5.4.1).
RST_STREAM 帧 MUST NOT 为处于 "idle" 状态的流发送. 如果收到标识空闲流的 RST_STREAM 帧, 接收者 MUST 将其视为 PROTOCOL_ERROR 类型的连接错误 (Section 5.4.1).
长度不是 4 个八位组的 RST_STREAM 帧 MUST 被视为 FRAME_SIZE_ERROR 类型的连接错误 (Section 5.4.1).
6.5. SETTINGS
SETTINGS 帧 (type=0x04) 传达影响端点通信方式的配置参数, 例如偏好以及对对等方行为的约束. SETTINGS 帧也用于确认收到这些设置. 单个 SETTINGS 帧中的配置参数称为一个 "setting".
设置并不协商; 它们描述发送对等方的特征, 供接收对等方使用. 每个对等方可以通告同一设置的不同值. 例如, 客户端可能设置较高的初始流量控制窗口, 而服务器可能设置较低的值以节省资源.
连接开始时两个端点 MUST 都发送 SETTINGS 帧, 并且在连接生命周期内任一端点 MAY 在任何其他时间发送 SETTINGS 帧. 实现 MUST 支持本规范定义的所有设置.
SETTINGS 帧中的每个参数都会替换该参数的任何现有值. 设置按出现顺序处理, SETTINGS 帧的接收方不需要维护除每个设置当前值以外的任何状态. 因此, SETTINGS 参数的值是接收方看到的最后一个值.
SETTINGS 帧由接收对等方确认. 为此, SETTINGS 帧定义 ACK 标志:
ACK (0x01): 设置时, ACK 标志表示该帧确认收到并应用对等方的 SETTINGS 帧. 设置此比特时, SETTINGS 帧的帧载荷 MUST 为空. 收到设置了 ACK 标志且长度字段值不为 0 的 SETTINGS 帧, MUST 被视为 FRAME_SIZE_ERROR 类型的连接错误 (Section 5.4.1). 更多信息见 Section 6.5.3 ("Settings Synchronization").
SETTINGS 帧始终应用于连接, 从不应用于单个流. SETTINGS 帧的流标识符 MUST 为零 (0x00). 如果端点收到 Stream Identifier 字段不是 0x00 的 SETTINGS 帧, 该端点 MUST 以 PROTOCOL_ERROR 类型的连接错误 (Section 5.4.1) 响应.
SETTINGS 帧影响连接状态. 格式错误或不完整的 SETTINGS 帧 MUST 被视为 PROTOCOL_ERROR 类型的连接错误 (Section 5.4.1).
长度不是 6 个八位组倍数的 SETTINGS 帧 MUST 被视为 FRAME_SIZE_ERROR 类型的连接错误 (Section 5.4.1).
6.5.1. SETTINGS 格式
SETTINGS 帧的帧载荷由零个或多个设置组成, 每个设置由一个无符号 16 位设置标识符和一个无符号 32 位值组成.
SETTINGS Frame {
Length (24),
Type (8) = 0x04,
Unused Flags (7),
ACK Flag (1),
Reserved (1),
Stream Identifier (31) = 0,
Setting (48) ...,
}
Setting {
Identifier (16),
Value (32),
}
Figure 7: SETTINGS Frame Format
Length、Type、Unused Flag(s)、Reserved 和 Stream Identifier 字段见 Section 4. SETTINGS 帧的帧载荷包含任意数量的 Setting 字段, 每个字段由以下内容组成:
Identifier: 一个 16 位设置标识符; 见 Section 6.5.2.
Value: 设置的 32 位值.
6.5.2. 已定义设置
定义了以下设置:
SETTINGS_HEADER_TABLE_SIZE (0x01): 此设置允许发送方告知远端端点用于解码字段块的压缩表的最大大小, 单位为八位组. 编码器可以通过字段块内特定于压缩格式的信令选择小于或等于该值的任意大小 (见 [COMPRESSION]). 初始值为 4,096 八位组.
SETTINGS_ENABLE_PUSH (0x02): 此设置可用于启用或禁用服务器推送. 如果服务器收到该参数被设置为 0, MUST NOT 发送 PUSH_PROMISE 帧; 见 Section 8.4. 已将此参数设置为 0 且该设置已被确认的客户端, MUST 将收到 PUSH_PROMISE 帧视为 PROTOCOL_ERROR 类型的连接错误 (Section 5.4.1).
SETTINGS_ENABLE_PUSH 的初始值为 1. 对客户端而言, 该值表示愿意接收 PUSH_PROMISE
帧. 对服务器而言, 该初始值没有效果, 等同于值 0. 任何非 0 或 1 的值 MUST 被视为
PROTOCOL_ERROR 类型的连接错误 (Section 5.4.1).
服务器 MUST NOT 明确将此值设置为 1. 服务器 MAY 在发送 SETTINGS 帧时省略此设置,
但如果服务器包含一个值, 该值 MUST 为 0. 客户端 MUST 将收到 SETTINGS_ENABLE_PUSH
设置为 1 的 SETTINGS 帧视为 PROTOCOL_ERROR 类型的连接错误 (Section 5.4.1).
SETTINGS_MAX_CONCURRENT_STREAMS (0x03): 此设置指示发送方允许的最大并发流数量. 该限制具有方向性: 它适用于发送方允许接收方创建的流数量. 初始情况下, 该值没有限制. 建议该值不小于 100, 以免不必要地限制并行性.
端点 SHOULD NOT 将 SETTINGS_MAX_CONCURRENT_STREAMS 的值 0 视为特殊值. 零值确实会
阻止创建新流; 但任何已被活跃流耗尽的限制也会产生同样效果. 服务器 SHOULD 只在短时间
内设置零值; 如果服务器不希望接受请求, 关闭连接更合适.
SETTINGS_INITIAL_WINDOW_SIZE (0x04): 此设置指示发送方用于流级流量控制的初始窗口大小 (单位为八位组). 初始值为 2^16-1 (65,535) 八位组.
此设置影响所有流的窗口大小 (见 Section 6.9.2).
超过最大流量控制窗口大小 2^31-1 的值 MUST 被视为 FLOW_CONTROL_ERROR 类型的连接错误
(Section 5.4.1).
SETTINGS_MAX_FRAME_SIZE (0x05): 此设置指示发送方愿意接收的最大帧载荷大小, 单位为八位组.
初始值为 2^14 (16,384) 八位组. 端点通告的值 MUST 位于该初始值与允许的最大帧大小
(2^24-1 或 16,777,215 八位组) 之间, 包含两端. 此范围之外的值 MUST 被视为
PROTOCOL_ERROR 类型的连接错误 (Section 5.4.1).
SETTINGS_MAX_HEADER_LIST_SIZE (0x06): 此建议性设置告知对等方发送方准备接受的最大字段段大小, 单位为八位组. 该值基于字段行的未压缩大小, 包括名称和值的八位组长度, 并为每个字段行加上 32 八位组开销.
对任何给定请求, MAY 强制执行低于所通告值的限制. 此设置的初始值为无限制.
收到包含任何未知或不支持标识符的 SETTINGS 帧的端点 MUST 忽略该设置.
6.5.3. 设置同步
SETTINGS 中的大多数值都受益于或需要理解对等方何时已接收并应用变更后的参数值. 为提供这样的同步时间点, 收到未设置 ACK 标志的 SETTINGS 帧时, 接收者 MUST 在收到后尽快应用更新后的设置. SETTINGS 帧按接收顺序确认.
SETTINGS 帧中的值 MUST 按出现顺序处理, 且值之间不得处理其他帧. 不支持的设置 MUST 被忽略. 一旦所有值都处理完毕, 接收者 MUST 立即发出设置了 ACK 标志的 SETTINGS 帧. 收到设置了 ACK 标志的 SETTINGS 帧后, 变更设置的发送方可以依赖最早的未确认 SETTINGS 帧中的值已经被应用.
如果 SETTINGS 帧的发送方未在合理时间内收到确认, MAY 发出 SETTINGS_TIMEOUT 类型的连接错误 (Section 5.4.1). 设置超时时, 需要为对等方的处理延迟留出余量; 如果超时仅基于端点之间的往返时间, 可能导致伪错误.
6.6. PUSH_PROMISE
PUSH_PROMISE 帧 (type=0x05) 用于提前通知对等端点发送方打算发起的流. PUSH_PROMISE 帧包含端点计划创建的流的无符号 31 位标识符, 以及为该流提供附加上下文的字段段. Section 8.4 对 PUSH_PROMISE 帧的使用有完整说明.
PUSH_PROMISE Frame {
Length (24),
Type (8) = 0x05,
Unused Flags (4),
PADDED Flag (1),
END_HEADERS Flag (1),
Unused Flags (2),
Reserved (1),
Stream Identifier (31),
[Pad Length (8)],
Reserved (1),
Promised Stream ID (31),
Field Block Fragment (..),
Padding (..2040),
}
Figure 8: PUSH_PROMISE Frame Format
Length、Type、Unused Flag(s)、Reserved 和 Stream Identifier 字段见 Section 4. PUSH_PROMISE 帧载荷具有以下附加字段:
Pad Length: 一个 8 位字段, 以八位组为单位包含帧填充长度. 该字段仅在设置 PADDED 标志时出现.
Promised Stream ID: 一个无符号 31 位整数, 标识被 PUSH_PROMISE 保留的流. 承诺流标识符 MUST 是发送方接下来发送的新流的有效选择 (见 Section 5.1.1 中的 "new stream identifier").
Field Block Fragment: 包含请求控制数据和头部段的字段块片段 (Section 4.3).
Padding: 不包含应用语义值的填充八位组. 发送时 Padding 八位组 MUST 设置为零. 接收方没有义务验证填充, 但 MAY 将非零填充视为 PROTOCOL_ERROR 类型的连接错误 (Section 5.4.1).
PUSH_PROMISE 帧定义以下标志:
PADDED (0x08): 设置时, PADDED 标志表示 Pad Length 字段及其描述的任何填充均存在.
END_HEADERS (0x04): 设置时, END_HEADERS 标志表示该帧包含完整字段块 (Section 4.3), 且后面不会跟随任何 CONTINUATION 帧.
未设置 END_HEADERS 标志的 PUSH_PROMISE 帧 MUST 后跟同一流上的 CONTINUATION 帧.
接收方 MUST 将收到任何其他类型帧或不同流上的帧视为 PROTOCOL_ERROR 类型的连接错误
(Section 5.4.1).
PUSH_PROMISE 帧 MUST 只在由对等方发起且处于 "open" 或 "half-closed (remote)" 状态的流上发送. PUSH_PROMISE 帧的流标识符指示它所关联的流. 如果 Stream Identifier 字段指定值 0x00, 接收者 MUST 以 PROTOCOL_ERROR 类型的连接错误 (Section 5.4.1) 响应.
承诺流不要求按被承诺的顺序使用. PUSH_PROMISE 只为稍后使用保留流标识符.
如果对等端点的 SETTINGS_ENABLE_PUSH 设置为 0, MUST NOT 发送 PUSH_PROMISE. 已设置此设置并已收到确认的端点, MUST 将收到 PUSH_PROMISE 帧视为 PROTOCOL_ERROR 类型的连接错误 (Section 5.4.1).
PUSH_PROMISE 帧的接收方可以通过返回引用承诺流标识符的 RST_STREAM 来拒绝承诺流, 并将其发回 PUSH_PROMISE 的发送方.
PUSH_PROMISE 帧以两种方式修改连接状态. 首先, 包含字段块 (Section 4.3) 可能修改为字段段压缩维护的状态. 其次, PUSH_PROMISE 还会保留一个流以供稍后使用, 使承诺流进入 "reserved (local)" 或 "reserved (remote)" 状态. 发送方 MUST NOT 在流上发送 PUSH_PROMISE, 除非该流是 "open" 或 "half-closed (remote)"; 发送方 MUST 确保承诺流是新流标识符 (Section 5.1.1) 的有效选择 (即承诺流 MUST 处于 "idle" 状态).
由于 PUSH_PROMISE 会保留流, 忽略 PUSH_PROMISE 帧会使流状态变得不确定. 接收方 MUST 将在既非 "open" 也非 "half-closed (local)" 的流上收到 PUSH_PROMISE 视为 PROTOCOL_ERROR 类型的连接错误 (Section 5.4.1). 但是, 已在关联流上发送 RST_STREAM 的端点 MUST 处理可能在 RST_STREAM 帧被接收和处理之前创建的 PUSH_PROMISE 帧.
接收方 MUST 将收到承诺非法流标识符 (Section 5.1.1) 的 PUSH_PROMISE 视为 PROTOCOL_ERROR 类型的连接错误 (Section 5.4.1). 请注意, 非法流标识符是指当前不处于 "idle" 状态的流标识符.
填充八位组总数由 Pad Length 字段值确定. 如果填充长度等于或大于帧载荷长度, 接收者 MUST 将其视为 PROTOCOL_ERROR 类型的连接错误 (Section 5.4.1).
| Note: 通过包含值为零的 Pad Length 字段, 可以将帧大小增加一个八位组.
6.7. PING
PING 帧 (type=0x06) 是一种用于测量发送方最小往返时间, 以及确定空闲连接是否仍可工作的机制. PING 帧可以由任何端点发送.
PING Frame {
Length (24) = 0x08,
Type (8) = 0x06,
Unused Flags (7),
ACK Flag (1),
Reserved (1),
Stream Identifier (31) = 0,
Opaque Data (64),
}
Figure 9: PING Frame Format
Length、Type、Unused Flag(s)、Reserved 和 Stream Identifier 字段见 Section 4.
除帧头部外, PING 帧 MUST 在帧载荷中包含 8 个八位组的不透明数据. 发送方可以包含其选择的任何值, 并以任何方式使用这些八位组.
未包含 ACK 标志的 PING 帧的接收方 MUST 以设置 ACK 标志且帧载荷相同的 PING 帧作为响应. PING 响应 SHOULD 比任何其他帧具有更高优先级.
PING 帧定义以下标志:
ACK (0x01): 设置时, ACK 标志表示该 PING 帧是 PING 响应. 端点 MUST 在 PING 响应中设置此标志. 端点 MUST NOT 响应包含此标志的 PING 帧.
PING 帧不与任何单个流关联. 如果收到的 PING 帧的 Stream Identifier 字段值不是 0x00, 接收者 MUST 以 PROTOCOL_ERROR 类型的连接错误 (Section 5.4.1) 响应.
收到长度字段值不是 8 的 PING 帧 MUST 被视为 FRAME_SIZE_ERROR 类型的连接错误 (Section 5.4.1).
6.8. GOAWAY
GOAWAY 帧 (type=0x07) 用于发起连接关闭或发出严重错误条件信号. GOAWAY 允许端点优雅地停止接受新流, 同时仍完成对先前已建立流的处理. 这支持服务器维护等管理操作.
端点开始新流与远端对等方发送 GOAWAY 帧之间存在固有竞态条件. 为处理这种情况, GOAWAY 包含发送端点在此连接上已处理或可能处理的最后一个由对等方发起的流的流标识符. 例如, 如果服务器发送 GOAWAY 帧, 被标识的流是客户端发起的编号最高的流.
发送 GOAWAY 后, 如果接收方发起的流的标识符高于所包含的最后流标识符, 发送方将忽略在这些流上发送的帧. GOAWAY 帧的接收方 MUST NOT 在连接上打开额外的流, 但可以为新流建立新连接.
如果 GOAWAY 的接收方已在流标识符高于 GOAWAY 帧所指示值的流上发送数据, 这些流未被处理或将不会被处理. GOAWAY 帧接收方可以将这些流视为从未创建过, 从而允许稍后在新连接上重试这些流.
端点 SHOULD 始终在关闭连接前发送 GOAWAY 帧, 以便远端对等方知道某个流是否已被部分处理. 例如, 如果 HTTP 客户端在服务器关闭连接的同时发送 POST, 若服务器未发送 GOAWAY 帧来指示它可能已经对哪些流采取了动作, 客户端就无法知道服务器是否已开始处理该 POST 请求.
端点可能选择在不发送 GOAWAY 的情况下关闭与行为异常的对等方的连接.
GOAWAY 帧不一定紧邻连接关闭之前; 收到 GOAWAY 且不再需要该连接的接收方, SHOULD 仍在终止连接前发送 GOAWAY 帧.
GOAWAY Frame {
Length (24),
Type (8) = 0x07,
Unused Flags (8),
Reserved (1),
Stream Identifier (31) = 0,
Reserved (1),
Last-Stream-ID (31),
Error Code (32),
Additional Debug Data (..),
}
Figure 10: GOAWAY Frame Format
Length、Type、Unused Flag(s)、Reserved 和 Stream Identifier 字段见 Section 4.
GOAWAY 帧不定义任何标志.
GOAWAY 帧应用于连接, 而不是特定流. 端点 MUST 将流标识符不是 0x00 的 GOAWAY 帧视为 PROTOCOL_ERROR 类型的连接错误 (Section 5.4.1).
GOAWAY 帧中的最后流标识符包含 GOAWAY 帧发送方可能已经对其采取过动作或可能仍会采取动作的编号最高流标识符. 直到并包括所标识流的所有流都可能以某种方式被处理. 如果没有流被处理, 最后流标识符可以设置为 0.
| Note: 在此上下文中, "processed" 表示来自流的某些数据已被传递给可能据此采取动作的
| 某个更高软件层.
如果连接在没有 GOAWAY 帧的情况下终止, 最后流标识符实际上是可能的最高流标识符.
对于编号小于或等于最后流标识符且在连接关闭前未完全关闭的流, 不能重新尝试请求、事务或任何协议活动, HTTP GET、PUT 或 DELETE 等幂等动作除外. 使用更高编号流的任何协议活动都可以使用新连接安全重试.
编号小于或等于最后流标识符的流上的活动仍可能成功完成. GOAWAY 帧的发送方可以通过发送 GOAWAY 帧优雅地关闭连接, 并保持连接处于 "open" 状态, 直到所有进行中的流完成.
如果情况发生变化, 端点 MAY 发送多个 GOAWAY 帧. 例如, 端点在优雅关闭期间发送带 NO_ERROR 的 GOAWAY 后, 随后可能遇到需要立即终止连接的条件. 收到的最后一个 GOAWAY 帧中的最后流标识符指示哪些流可能已被处理. 端点 MUST NOT 增加其在最后流标识符中发送的值, 因为对等方可能已经在另一个连接上重试未处理的请求.
无法重试请求的客户端会丢失服务器关闭连接时所有正在传输中的请求. 对于可能未使用 HTTP/2 服务客户端的中介, 尤其如此. 尝试优雅关闭连接的服务器 SHOULD 先发送一个最后流标识符设为 2^31-1 且错误码为 NO_ERROR 的 GOAWAY 帧. 这向客户端发出关闭即将发生且禁止发起更多请求的信号. 在为任何传输中的流创建留出时间后 (至少一个往返时间), 服务器 MAY 发送另一个带更新后最后流标识符的 GOAWAY 帧. 这确保连接可以在不丢失请求的情况下干净关闭.
发送 GOAWAY 帧后, 发送方可以丢弃接收方发起且标识符高于所标识最后流的流上的帧. 但是, 任何改变连接状态的帧不能被完全忽略. 例如, HEADERS、PUSH_PROMISE 和 CONTINUATION 帧 MUST 被最低限度处理, 以确保为字段段压缩维护的状态保持一致 (见 Section 4.3); 类似地, DATA 帧 MUST 计入连接流量控制窗口. 未处理这些帧可能导致流量控制或字段段压缩状态不同步.
GOAWAY 帧还包含一个 32 位错误码 (Section 7), 其中包含关闭连接的原因.
端点 MAY 将不透明数据附加到任何 GOAWAY 帧的帧载荷中. 附加调试数据仅用于诊断目的, 不携带语义值. 调试信息可能包含安全或隐私敏感数据. 记录或以其他方式持久存储的调试数据 MUST 具有充分保护措施, 以防止未授权访问.
6.9. WINDOW_UPDATE
WINDOW_UPDATE 帧 (type=0x08) 用于实现流量控制; 概述见 Section 5.2.
流量控制在两个层级运行: 每个单独流上以及整个连接上.
两种流量控制都是逐跳的, 也就是只在两个端点之间. 中介不会在依赖连接之间转发 WINDOW_UPDATE 帧. 但是, 任何接收方对数据传输的节流都可能间接导致流量控制信息向原始发送方传播.
流量控制只适用于被标识为受流量控制约束的帧. 在本文档定义的帧类型中, 这只包括 DATA 帧. 不受流量控制约束的帧 MUST 被接受并处理, 除非接收方无法为处理该帧分配资源. 如果接收方无法接受某个帧, MAY 以 FLOW_CONTROL_ERROR 类型的流错误 (Section 5.4.2) 或连接错误 (Section 5.4.1) 响应.
WINDOW_UPDATE Frame {
Length (24) = 0x04,
Type (8) = 0x08,
Unused Flags (8),
Reserved (1),
Stream Identifier (31),
Reserved (1),
Window Size Increment (31),
}
Figure 11: WINDOW_UPDATE Frame Format
Length、Type、Unused Flag(s)、Reserved 和 Stream Identifier 字段见 Section 4. WINDOW_UPDATE 帧的帧载荷是一个保留比特加一个无符号 31 位整数, 表示除现有流量控制窗口之外, 发送方还可以传输的八位组数量. 流量控制窗口增量的合法范围是 1 到 2^31-1 (2,147,483,647) 八位组.
WINDOW_UPDATE 帧不定义任何标志.
WINDOW_UPDATE 帧可以特定于某个流, 也可以适用于整个连接. 在前一种情况下, 帧的流标识符指示受影响的流; 在后一种情况下, 值 "0" 表示该帧的对象是整个连接.
接收方 MUST 将收到流量控制窗口增量为 0 的 WINDOW_UPDATE 帧视为 PROTOCOL_ERROR 类型的流错误 (Section 5.4.2); 连接流量控制窗口上的错误 MUST 被视为连接错误 (Section 5.4.1).
WINDOW_UPDATE 可以由已发送设置 END_STREAM 标志帧的对等方发送. 这意味着接收方可能在处于 "half-closed (remote)" 或 "closed" 状态的流上收到 WINDOW_UPDATE 帧. 接收方 MUST NOT 将其视为错误 (见 Section 5.1).
接收方收到受流量控制帧时, MUST 始终将其贡献计入连接流量控制窗口, 除非接收方将其视为连接错误 (Section 5.4.1). 即使该帧存在错误, 这也是必要的. 发送方会将该帧计入流量控制窗口, 但如果接收方不这样做, 发送方和接收方的流量控制窗口可能变得不同.
长度不是 4 个八位组的 WINDOW_UPDATE 帧 MUST 被视为 FRAME_SIZE_ERROR 类型的连接错误 (Section 5.4.1).
6.9.1. 流量控制窗口
HTTP/2 中的流量控制通过每个发送方在每个流上保留的窗口实现. 流量控制窗口是一个简单整数值, 指示发送方被允许传输多少八位组数据; 因此, 其大小是接收方缓冲能力的度量.
适用两个流量控制窗口: 流流量控制窗口和连接流量控制窗口. 发送方 MUST NOT 发送长度超过接收方通告的任一流量控制窗口可用空间的受流量控制帧. 如果任一流量控制窗口中没有可用空间, MAY 发送设置 END_STREAM 标志的零长度帧 (即空 DATA 帧).
进行流量控制计算时, 不计入 9 八位组帧头部.
发送受流量控制帧后, 发送方按已传输帧的长度减少两个窗口中的可用空间.
帧的接收方在消费数据并释放流量控制窗口中的空间时发送 WINDOW_UPDATE 帧. 会分别为流级和连接级流量控制窗口发送单独的 WINDOW_UPDATE 帧. 建议接收方具备机制, 以避免发送增量非常小的 WINDOW_UPDATE 帧; 见 [RFC1122] Section 4.2.3.3.
收到 WINDOW_UPDATE 帧的发送方按帧中指定的数量更新相应窗口.
发送方 MUST NOT 允许流量控制窗口超过 2^31-1 八位组. 如果发送方收到导致流量控制窗口超过此最大值的 WINDOW_UPDATE, MUST 视情况终止流或连接. 对于流, 发送方发送带 FLOW_CONTROL_ERROR 错误码的 RST_STREAM; 对于连接, 发送带 FLOW_CONTROL_ERROR 错误码的 GOAWAY 帧.
发送方的受流量控制帧和接收方的 WINDOW_UPDATE 帧彼此完全异步. 这一属性允许接收方积极更新发送方维护的窗口大小, 以防止流停滞.
6.9.2. 初始流量控制窗口大小
首次建立 HTTP/2 连接时, 新流以 65,535 八位组的初始流量控制窗口大小创建. 连接流量控制窗口也是 65,535 八位组. 两个端点都可以通过在 SETTINGS 帧中包含 SETTINGS_INITIAL_WINDOW_SIZE 值来调整新流的初始窗口大小. 连接流量控制窗口只能使用 WINDOW_UPDATE 帧改变.
在收到设置 SETTINGS_INITIAL_WINDOW_SIZE 值的 SETTINGS 帧之前, 端点在发送受流量控制帧时只能使用默认初始窗口大小. 类似地, 在收到 WINDOW_UPDATE 帧之前, 连接流量控制窗口基于默认初始窗口大小设置.
除了改变尚未活跃流的流量控制窗口外, SETTINGS 帧还可以改变具有活跃流量控制窗口的流 (即处于 "open" 或 "half-closed (remote)" 状态的流) 的初始流量控制窗口大小. 当 SETTINGS_INITIAL_WINDOW_SIZE 的值变化时, 接收方 MUST 按新值与旧值之间的差值调整其维护的所有流流量控制窗口大小.
SETTINGS_INITIAL_WINDOW_SIZE 的变化可能导致流量控制窗口中的可用空间变为负数. 发送方 MUST 跟踪负的流量控制窗口, 并且在收到使流量控制窗口变为正数的 WINDOW_UPDATE 帧之前, MUST NOT 发送新的受流量控制帧.
例如, 如果客户端在连接建立后立即发送 60 KB, 而服务器将初始窗口大小设置为 16 KB, 客户端在收到 SETTINGS 帧时会将可用流量控制窗口重新计算为 -44 KB. 客户端会保留负的流量控制窗口, 直到 WINDOW_UPDATE 帧将窗口恢复为正数, 之后客户端才能继续发送.
SETTINGS 帧不能改变连接流量控制窗口.
端点 MUST 将导致任何流量控制窗口超过最大大小的 SETTINGS_INITIAL_WINDOW_SIZE 变更视为 FLOW_CONTROL_ERROR 类型的连接错误 (Section 5.4.1).
6.9.3. 减小流窗口大小
希望使用比当前大小更小的流量控制窗口的接收方可以发送新的 SETTINGS 帧. 但是, 接收方 MUST 准备好接收超过此窗口大小的数据, 因为发送方可能在处理 SETTINGS 帧之前发送超过较低限制的数据.
发送降低初始流量控制窗口大小的 SETTINGS 帧后, 接收方 MAY 继续处理超过流量控制限制的流. 允许流继续并不会让接收方立即减少为流量控制窗口保留的空间. 这些流的进展也可能停滞, 因为需要 WINDOW_UPDATE 帧来允许发送方恢复发送. 接收方 MAY 改为对受影响流发送带 FLOW_CONTROL_ERROR 错误码的 RST_STREAM.
6.10. CONTINUATION
CONTINUATION 帧 (type=0x09) 用于继续字段块片段序列 (Section 4.3). 只要前一个帧位于同一流上, 并且是未设置 END_HEADERS 标志的 HEADERS、PUSH_PROMISE 或 CONTINUATION 帧, 就可以发送任意数量的 CONTINUATION 帧.
CONTINUATION Frame {
Length (24),
Type (8) = 0x09,
Unused Flags (5),
END_HEADERS Flag (1),
Unused Flags (2),
Reserved (1),
Stream Identifier (31),
Field Block Fragment (..),
}
Figure 12: CONTINUATION Frame Format
Length、Type、Unused Flag(s)、Reserved 和 Stream Identifier 字段见 Section 4. CONTINUATION 帧载荷包含字段块片段 (Section 4.3).
CONTINUATION 帧定义以下标志:
END_HEADERS (0x04): 设置时, END_HEADERS 标志表示该帧结束一个字段块 (Section 4.3).
如果未设置 END_HEADERS 标志, 该帧 MUST 后跟另一个 CONTINUATION 帧. 接收方 MUST 将
收到任何其他类型帧或不同流上的帧视为 PROTOCOL_ERROR 类型的连接错误 (Section 5.4.1).
CONTINUATION 帧按 Section 4.3 中的定义改变连接状态.
CONTINUATION 帧 MUST 与流关联. 如果收到的 CONTINUATION 帧的 Stream Identifier 字段为 0x00, 接收者 MUST 以 PROTOCOL_ERROR 类型的连接错误 (Section 5.4.1) 响应.
CONTINUATION 帧之前 MUST 是未设置 END_HEADERS 标志的 HEADERS、PUSH_PROMISE 或 CONTINUATION 帧. 观察到违反此规则的接收者 MUST 以 PROTOCOL_ERROR 类型的连接错误 (Section 5.4.1) 响应.
第 6 章完成!