(三) HTTP/2的帧

来源:互联网 发布:微盘商城源码 编辑:程序博客网 时间:2024/05/26 19:16

HTTP/2的连接建立之后,两个端点之间就可以开始交换“帧”了。

帧的格式

 +-----------------------------------------------+ |                 Length (24)                   | +---------------+---------------+---------------+ |   Type (8)    |   Flags (8)   | +-+-------------+---------------+-------------------------------+ |R|                 Stream Identifier (31)                      | +=+=============================================================+ |                   Frame Payload (0...)                      ... +---------------------------------------------------------------+

帧的格式如上图所示。所有的帧都以一个9字节的帧头开始,后面跟随变长的有效载荷。

帧头的字段定义如下:

  • Length:帧的有效载荷长度,以无符号24位整数表示。除非接收者为SETTINGS_MAX_FRAME_SIZE设置一个更大的值,否则,长度不能大于2^14
    (16,384)。9字节的帧头并不计算在长度之内。
  • Type:8位,帧类型。帧类型决定了帧的格式和语义。任何未知的帧类型都将被忽略和丢弃。
  • Flags:8位,为与帧类型相关的布尔型标识保留的字段。根据所指示的帧类型的不同,布尔标识被赋予不同的语义。某个帧类型的没有定义语义的布尔标识必须被忽略,并且在发送时必须保持未设置状态(0x0)。
  • R:1位,保留字段。这个字段的语义未定义,在发送时必须保持未设置状态(0x0),在接收时必须被忽略掉。
  • Stream Identifier:流标识符,以无符号31位整数表示。值0x0被保留,表明帧是与整个连接关联的,而不是与某个流关联。

帧的有效载荷的结构和内容完全依赖于帧类型。

帧的大小

帧的有效载荷的大小受接收者在SETTINGS_MAX_FRAME_SIZE设置中公告的最大值限制。这个设置可以是2^14 (16,384) 和 2^24-1(16,777,215)字节之间的任意值。

所有HTTP/2的实现都必须有能力接收并且最低限度能处理多达2^14字节长度(外加9字节长度的帧头)的帧。当描述帧的大小时,帧头的大小的不包含在内的。某些帧类型,例如PING帧,对有效载荷的数据大小添加了额外的限制。

如果帧超出了SETTINGS_MAX_FRAME_SIZE定义的最大长度,或者超出帧类型定义的任何限制,或者太小而无法包含强制帧数据,端点都必须发送一个FRAME_SIZE_ERROR错误码。帧中能够修改整个连接状态的帧大小错误必须被视为一个连接错误;这包括所有携带报头块(也就是HEADERS,PUSH_PROMISE和CONTINUATION)或SETTINGS的帧,以及所有流标识符是0的帧。

端点没有义务使用帧中的全部可用空间。使用小于最大长度的帧可以提高响应性。在发送时间敏感的帧(例如,RST_STREAM,WINDOW_UPDATE或PRIORITY)时,发送大尺寸的帧会导致延迟。如果被一个大帧阻塞传输,那么会影响性能。

报头压缩和解压缩

与HTTP1.x一样,HTTP/2的报头字段包含一个名字和一个或多个值。报头字段在HTTP请求和响应中使用,也在服务端推送操作中使用。

报头列表是0个或多个报头字段的集合。当在一个连接上传输时,利用HTTP报头压缩,报头列表被序列化为一个报头块。然后,序列化的报头块被切分为一个或多个字节序列(称为“报头块碎片”),再作为HEADERS,PUSH_PROMISE或CONTINUATION等帧的有效载荷被传输出去。

Cookie报头字段通过HTTP映射特殊处理。

接收端通过连接碎片重组报头块,然后解压缩报头块来重建报头列表。

一个完整的报头块包含:

  • 一个设置了END_HEADERS标识的HEADERS或PUSH_PROMISE帧,或者
  • 一个清楚了END_HEADERS标识的HEADERS或PUSH_PROMISE帧,以及一个或多个CONTINUATION帧,其中,最后一个CONTINUATION帧设置了END_HEADERS标识。

报头压缩是有状态的。在整个连接中,使用一个压缩上下文和一个解压缩上下文。报头块中的解码错误必须被视为一个COMPRESSION_ERROR类型的连接错误。

每个报头块被作为离散单元处理。报头块必须作为连续的帧序列传输,没有任何类型或任何其它流的交错帧。在HEADERS或CONTINUATION帧序列中的最后一个帧必须设置END_HEADERS标识。在PUSH_PROMISE或CONTINUATION帧序列中的最后一个帧必须设置END_HEADERS标识。这允许一个报头块在逻辑上等价于一个独立帧。

报头块碎片只能作为HEADERS,PUSH_PROMISE或CONTINUATION帧的有效载荷,这是因为这些帧携带了能够修改接收端维护的压缩上下文的数据。接收 HEADERS,PUSH_PROMISE或CONTINUATION帧的端点需要重组报头块并执行解压缩操作,即使这些帧将被丢弃。如果接收端没有解压缩报头块,那么它必须以一个类型是COMPRESSION_ERROR的连接错误终止连接。

0 0
原创粉丝点击