go HTTP2 头部压缩算法hpack
Duslia 人气:0Hpack 是啥
Hpack 是 HTTP2 的头部压缩算法。在 HTTP1 中,每次传输都会有大量的 Header 携带,我们可以拿一个实际的请求来看,如图一:
图一:请求 header
这里面 Header 很多是请求共性的,比如 method: POST,就是 post 请求的 header,那每个 POST 请求都会携带这个 header;以及同一个页面里可能有很多请求需要带上相同 header,比如 user-agent、鉴权相关 header 等等。那如果 body 很小的话,每次传输利用率就很低了。HTTP2 为了提高传输效率设计了 HPACK 头部压缩算法。
HPACK 原理
HPACK 维护了两张表,静态表和动态表。如果 Header key、value 在表里的话,直接将 Header kv 用 index 编码即可;如果不存在表中的话,则采用 Huffman 编码或者不编码发送。每条连接维护各自的动态表,request 和 response 的动态表是分开的。
静态表存储常见的 Header kv,比如 :method: GET、:method: POST、:schema: http 等一共 61 项,具体的项可以参考 RFC 7541 文档。
动态表是一个先进先出的表,先进入的在高索引空间,后进入的在低索引空间(索引空间从0到最后递减)。header 根据一定的规则判断是否加入动态表,有三种规则:
- 将 header 字段添加到动态表的开头
- 不将 header 字段添加到动态表
- 不将 header 添加到动态表,另外规定 header 始终不被动态表编码,常见于有代理或者网关的场景。这是为了保护 header 字段值,比如通过大量尝试判断 header size 可以推断出动态表的内容。
动态表也有一定大小,通过 SETTINGS_HEADER_TABLE_SIZE 来设置。如果新的 Header kv size 超过了这个值,就会逐出动态表,直到能够放下这个 Header kv 或者将所有的逐出。特别的,如果一个 Header kv size 大于了动态表的最大值,那么这个 Header 的作用就是清空动态表。
如何编码
- 该 Header 已经存在动态表中
0 1 2 3 4 5 6 7 +---+---+---+---+---+---+---+---+ | 1 | Index (7+) | +---+---------------------------+
- Key 被索引,value 未索引且允许保存
0 1 2 3 4 5 6 7 +---+---+---+---+---+---+---+---+ | 0 | 1 | Index (6+) | +---+---+-----------------------+ | H | Value Length (7+) | +---+---------------------------+ | Value String (Length octets) | +-------------------------------+
01 后的 index 表示 Header Key 的索引
这个 Header 会被加在 server 和 client 的动态表中。
- Key 被索引,value 未索引且不允许保存
0 1 2 3 4 5 6 7 +---+---+---+---+---+---+---+---+ | 0 | 0 | 0 | 0 | Index (4+) | +---+---+-----------------------+ | H | Value Length (7+) | +---+---------------------------+ | Value String (Length octets) | +-------------------------------+
- Key、value 均未索引且允许保存
0 1 2 3 4 5 6 7 +---+---+---+---+---+---+---+---+ | 0 | 1 | 0 | +---+---+-----------------------+ | H | Name Length (7+) | +---+---------------------------+ | Name String (Length octets) | +---+---------------------------+ | H | Value Length (7+) | +---+---------------------------+ | Value String (Length octets) | +-------------------------------+
- Key、value 均未索引且不允许保存
0 1 2 3 4 5 6 7 +---+---+---+---+---+---+---+---+ | 0 | 0 | 0 | 0 | 0 | +---+---+-----------------------+ | H | Name Length (7+) | +---+---------------------------+ | Name String (Length octets) | +---+---------------------------+ | H | Value Length (7+) | +---+---------------------------+ | Value String (Length octets) | +-------------------------------+
- Key 被索引,value 未索引且绝对不允许保存
0 1 2 3 4 5 6 7 +---+---+---+---+---+---+---+---+ | 0 | 0 | 0 | 1 | Index (4+) | +---+---+-----------------------+ | H | Value Length (7+) | +---+---------------------------+ | Value String (Length octets) | +-------------------------------+
- Key、value 均未索引且绝对不允许保存
0 1 2 3 4 5 6 7 +---+---+---+---+---+---+---+---+ | 0 | 0 | 0 | 1 | 0 | +---+---+-----------------------+ | H | Name Length (7+) | +---+---------------------------+ | Name String (Length octets) | +---+---------------------------+ | H | Value Length (7+) | +---+---------------------------+ | Value String (Length octets) | +-------------------------------+
举个编码
加载全部内容