我在不同的终端上使用wireshark解码相同的pcap文件。而我有不同的输出
Stream: HEADERS, Stream ID: 1537, Length 7, 200 OK
Length: 7
Type: HEADERS (1)
Flags: 0x04, End Headers
0... .... .... .... .... .... .... .... = Reserved: 0x0
.000 0000 0000 0000 0000 0110 0000 0001 = Stream Identifier: 1537
[Pad Length: 0]
Header Block Fragment: 88c00f0d023236
[Header Length: 78]
[Header Count: 3]
Header: :status: 200 OK
Header: content-type: application/json
Header: content-length: 26
输入图片描述
我检查十六进制蒸汽和索引第二个不同的头是相同的。那么是什么导致了不同呢?
HTTP/2报头使用HPACK压缩。这使用了许多技术来压缩头,包括引用预定义的静态表,使用动态表,以及使用霍夫曼编码而不是纯ASCII。
HPACK静态表有61个常用的头和值。说"使用静态条目8"比说":status: 200
"更快。
动态表是静态表的扩展,但是是在连接上建立的。因此,第一次看到的新头被添加到索引62。说"见header 62,我之前发给你的"要比说"user-agent: Mozilla/5.0 (Macintosh;Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36"一次,一次,一次
然而,动态表随着每个新标头被移动——也就是说,下一个新标头被添加索引62,而位置62的旧标头现在变成63。这允许最老的头在达到最大大小后最终从表中删除。
所有这些都意味着两个报头块解码为不同的值并不意外,因为动态表在不断移动。事实上,很少有两个HPACK报头解码成完全相同的东西(这意味着要么只使用了静态查找,要么在两个请求之间没有改变动态报头)。
为了证明这是一个问题,让我们解码这个报头块:
88c00f0d023236
我们需要在二进制中查看这一点,因为HPACK并不总是使用离散的8位块(特别是在使用霍夫曼编码时):
10001000110000000000111100001101000000100011001000110110
有各种类型的HPACK报头字段:
我们从一个1
开始,所以我们知道第一个报头字段是一个索引报头字段表示,所以接下来的7位给出索引值(0001000
或8),因为它小于62,是在HPACK静态表中,查找它,我们看到它是:status: 200
。
接下来我们有11000000
,这也是索引值1000000
或64的索引头字段表示(以1
开头)。这超出了61个预定义的静态标头,因此在动态表中。如上所述,对于每个请求,这可能是不同的。这是您的c0
值,并解释了它。在第一个请求中,动态表必须有content-type: application/json
,在64位,而在第二个请求中,它必须有status: 503
在64位(尽管我不明白的一件事是为什么第二个例子有两个状态码?)。
之后,只是为了显示下一个标题是预期的,我没有编造这一切,我们有00001111...
。它以0000
开头,所以它是一个没有索引的字面头字段(这意味着这个头不应该被添加到动态表中,因为它不太可能再次被需要)。接下来的4位数字是1111,这是索引15 +接下来的8位(00001101
= 13),所以它的头15 + 13 = 29,这是在静态表作为content-length
(这就是为什么它有意义为什么他们没有把它添加到表中,因为内容长度值可能是高度可变的请求之间)。接下来我们看一下这个头(00000010
)的值。这从0
开始,所以我们知道它不是霍夫曼编码,它的长度是2。所以我们看看接下来的2个八位字节,这将是ASCII编码,而不是霍夫曼:00110010
(或十进制50),它查找一个ASCII表是数字2
,然后00110110
(或十进制54),这是数字6
在ASCII中。所以我们最终得到content-length: 26
,这确实是我们看到的。
所以两个例子都以:status: 200
开始,以content-length: 26
结束,它们都不使用动态表,所以它们可以是相同的。
的不同之处在于中间的位,在这两种情况下,它都指的是当时动态表位置为64的东西。这在不同的时间会有所不同。因此,相同编码的HPACK报头有不同的值。