HTTP2于2015年2月28日正式通过IETF组织批准发布,正式定稿。有关它的内容可以参考: HTTP2 概述
在HTTP2 的网络通讯中, Frame 是 通讯中的最小传输单位,至少含有一个 Frame header,能够表示它属于哪一个 Stream。一个具体的请求类似如下:

帧头+负载的比特位通用结构:

帧头为固定的9个字节((24+8+8+1+31)/8=9)呈现,变化的为帧的负载(Frame Payload),负载内容是由帧类型(Type)定义。

关于帧长度,需要稍加关注: - 0 ~ 2^14(16384)为默认约定长度,所有端点都需要遵守 - 2^14 (16,384) ~ 2^24-1(16,777,215)此区间数值,需要接收方设置SETTINGS_MAX_FRAME_SIZE参数单独赋值 - 一端接收到的帧长度超过设定上限或帧太小,需要发送FRAME_SIZE_ERR错误 - 当帧长错误会影响到整个连接状态时,须以连接错误对待之;比如HEADERS,PUSH_PROMISE,CONTINUATION,SETTINGS,以及帧标识符不该为0的帧等,都需要如此处理 - 任一端都没有义务必须使用完一个帧的所有可用空间 - 大帧可能会导致延迟,针对时间敏感的帧,比如RST_STREAM, WINDOW_UPDATE, PRIORITY,需要快速发送出去,以免延迟导致性能等问题
HTTP2 的帧包含下面几种类型,对应上图的Type区域定义。
参考:
HTTP/2 frame format
帧的标志位(Flags)含义如下图:
图来自: http://search.cpan.org/~crux/Protocol-HTTP2-0.14/lib/Protocol/HTTP2/Frame.pm

假设我们要发送 0x12345678,流编号为 10 ,类型为DATA,那么这个Frame的16进制表达就是:
'000004' + '00' + '00' + '0000000A' + '12345678'
HTTP2的 HEADER帧的格式如下:

对应的字段列表说明如下:
- Pad Length:受制于PADDED标志控制是否显示,8个比特表示填充的字节数。 可选。Flags:PADDED 设置后要求有此字段
- E:一个比特表示流依赖是否专用,可选项,只在流优先级PRIORITY被设置时有效 可选。Flags:PRIORITY 设置后要有此字段
- Stream Dependency:31个比特表示流依赖,只在流优先级PRIORITY被设置时有效 可选。Flags:PRIORITY 设置后要有此字段
- Weight:8个比特(一个字节)表示无符号的自然数流优先级,值范围自然是(1~256),或称之为权重。只在流优先级PRIORITY被设置时有效 这个字段是可选的,并且只在优先级标记设置的情况下才呈现。
- Header Block Fragment:报头块分片
- Padding:填充的字节,受制于PADDED标志控制是否显示,长度由Pad Length字段决定
注意, 只有 Header Block Fragment 是必须的, 其他都看 帧的标志位Flags 是否设置要有。
所需标志位:
注意事项:
- 其负载为报头块分片,若内容过大,需要借助于CONTINUATION帧继续传输。若流标识符为0x0,结束段需要返回PROTOCOL_ERROR连接异常。HEADERS帧包含优先级信息是为了避免潜在的不同流之间优先级顺序的干扰。
- 其实一般来讲,报文头部不大的情况下,一个HEADERS就可以完成了,特殊情况就是Cookie字段超过16KiB大小,不常见。
HTTP2的 CONTINUATION 帧的格式如下:

字段列表:
- Header Block Fragment,用于协助HEADERS/PUSH_PROMISE等单帧无法包含完整的报头剩余部分数据。
注意事项:
- 一个HEADERS/PUSH_PROMISE帧后面会跟随零个或多个CONTINUATION,只要上一个帧没有设置END_HEADERS标志位,就不算一个帧完整数据的结束。
- 接收端处理此种情况,从开始的HEADERS/PUSH_PROMISE帧到最后一个包含有END_HEADERS标志位帧结束,合并的数据才算是一份完整数据拷贝
- 在HEADERS/PUSH_PROMISE(没有END_HEADERS标志位)和CONTINUATION帧中间,是不能够掺杂其它帧的,否则需要报PROTOCOL_ERROR错误
标志位: * END_HEADERS(0X4):表示报头块的最后一个帧,否则后面还会跟随CONTINUATION帧。
一个或多个DATA帧作为请求、响应内容载体,较为完整的结构如下:

字段:
标志位:
注意事项:
- 若流标识符为0x0,接收者需要响应PROTOCOL_ERROR连接错误
- DATA帧只能在流处于"open" or "half closed (remote)"状态时被发送出去,否则接收端必须响应一个STREAM_CLOSED的连接错误。若填充长度不小于负载长度,接收端必须响应一个PROTOCOL_ERROR连接错误。
例子
以gRPC的 HelloWorld 项目为例, 有关这个项目的搭建请参考
其中一个网络请求包的内容如下图截图:
这是来自 CommView 的 Loopback 网络请求监控的包, 如何使用 CommView 请参考

这里黑色加量的部分是 RPC 特有的部分内容。
这部分包含2个帧,他们的分别数据如下:
00 00-0E 01 04 00 00 00 01 88 5F 8B 1D 75 D0 62 0D 26-3D 4C 4D 65 64
00 00 12 00 00 00 00 00 01 00 00-00 00 0D 0A 0B 48 65 6C 6C 6F 20 77 6F 72 6C 64
Header 帧
00 00 0E 01 04 00 00 00 01 88 5F 8B 1D 75 D0 62 0D 26 3D 4C 4D 65 64
帧长度Length 为 00 00 0E ,即 14 + 9 长度共23 。
帧类型Type 为 01 标示是 Header 帧
帧的标志位Flags 为 04, 标示 END_HEADERS, 即这个Header帧不需要分片。
流标识符Stream Identifier 为 00 00 00 01 即,编号为1 。
Header 帧特有的串(Header Block Fragment): 88 5F 8B 1D 75 D0 62 0D 26 3D 4C 4D 65 64
这里做了压缩,就不展开了, 相关知识请参考:https://www.cdsy.xyz/computer/servers/ns/250213/cd73604.html
Data帧
00 00 12 00 00 00 00 00 01 00 00 00 00 0D 0A 0B 48 65 6C 6C 6F 20 77 6F 72 6C 64
帧长度Length 为 00 00 12 即 18+9 = 27
帧类型Type 为 00 标示是 Data 帧
帧的标志位Flags 00
流标识符Stream Identifier 为 00 00 00 01 ,及 编号1, 对应上面的 Header 帧。
Data帧特有的串(Data 区域): 00 00 00 00 0D 0A 0B 48 65 6C 6C 6F 20 77 6F 72 6C 64
参考资料:
HTTP2协议中报文头可以采用Haffman编码,我们看到的报文头信息都是二进制信息。
HTTP2的报文格式请参考: http://www.blogjava.net/yongboy/archive/2015/03/20/423655.html
HTTP2报文头及数据帧格式解析实例分析
Haffman 压缩算法请参考: https://www.cdsy.xyz/computer/programme/algorithm/250214/cd73606.html

