HTTP/2 头部压缩核心:HPACK 算法全解析

一、HPACK 如何减少 HTTP 头部的大小

HTTP/1.1 的头部是明文重复传输 (比如每次请求都带Host: example.comUser-Agent: Chrome/...),占带宽且冗余;HPACK 是 HTTP/2 的头部压缩算法,通过 3 个核心机制减少头部体积:

1. 静态字典(Static Dictionary)

  • 原理 :预定义 61 个高频头部字段(如:method=GET:path=/Host),用索引编号 代替完整字符串。
    • 示例:传输:method: GET时,直接用编号 2(静态字典中2 → :method: GET),仅占 1 字节,替代原本的 11 字节明文。
  • 优势:高频头部无需重复传输完整字段,直接用索引压缩。

2. 动态字典(Dynamic Dictionary)

  • 原理 :连接过程中,双方维护一个动态更新的字典 ,将本次请求 / 响应中出现的新头部(如X-Custom-Header: value)存入字典,后续传输时用索引代替。
    • 示例:首次传输X-Token: abc123(占 14 字节),存入动态字典索引 62;下次传输时直接用 62,仅占 1 字节。
  • 优势:针对业务自定义头部,实现 "一次传输、多次复用" 的压缩。

3. Huffman 编码

  • 原理 :对头部的值(或未在字典中的字段名) 用 Huffman 树进行变长编码 (高频字符用短码,低频字符用长码),进一步压缩字节数。
    • 示例:字符串example.com的 ASCII 编码占 11 字节,Huffman 编码后可压缩至 8 字节左右。

我们拆解 example.com 的哈夫曼压缩过程:

HPACK 内置了一份 预定义的静态哈夫曼码表 ,表中对 HTTP 头部常见的字符(比如 a-z.-: 等)分配了不等长的二进制编码------ 出现频率越高的字符,编码越短。

  • 高频字符(如 eac):短编码(比如 3~4 位)
  • 低频字符(如 xz_):长编码(比如 5~8 位)

example.com 拆分为单个字符:e x a m p l e . c o m,共 11 个 ASCII 字符(每个 ASCII 字符占 1 字节 = 8 位,原始总长度 11×8=88 位)。

我们对照 HPACK 静态哈夫曼码表的高频字符编码规则(简化版):

字符 出现频率 HPACK 哈夫曼编码(二进制) 编码长度(位)
e 极高 00 2
a 010 3
m 0110 4
p 1001 4
l 1010 4
x 中低 11001 5
. 1011 4
c 0111 4
o 11000 5

我们把 example.com 的每个字符替换成哈夫曼编码,再统计总位数:

  1. e00 → 2 位
  2. x11001 → 5 位
  3. a010 → 3 位
  4. m0110 → 4 位
  5. p1001 → 4 位
  6. l1010 → 4 位
  7. e00 → 2 位
  8. .1011 → 4 位
  9. c0111 → 4 位
  10. o11000 → 5 位
  11. m0110 → 4 位

总位数 = 2+5+3+4+4+4+2+4+4+5+4 = 41 位

  • 原始长度:11 个 ASCII 字符 = 88 位 = 11 字节
  • 哈夫曼编码后长度:41 位 ≈ 5.125 字节
  • 实际压缩到 8 字节的补充 :哈夫曼编码后的二进制流需要按 字节(8 位)对齐 存储,同时 HPACK 会给编码结果加一个 1~2 字节的「编码类型标识」(告诉解码器这是哈夫曼编码的字符串)。加上对齐和标识的开销后,总长度就变成了 8 字节左右,比原始 11 字节少了 3 字节。
  • 优势:对非字典字段的文本内容,额外减少 30%~50% 的体积。

最终效果

  • 典型 HTTP 请求头部(约 200 字节),经 HPACK 压缩后可降至50 字节以内,压缩率达 75% 以上;
  • 重复请求的头部(如同一页面的资源请求),压缩率可接近 90%。

二、HPACK 中如何使用 Huffman 树

HPACK 的 Huffman 树是预定义的静态树(RFC 7541 附录 C),双方无需协商,直接使用,流程如下:

1. Huffman 树的结构

  • 树的叶子节点对应可打印 ASCII 字符 + 部分控制字符(共 256 个可能字符);
  • 每个字符对应唯一的二进制编码 ,编码长度与字符出现频率负相关:
    • 高频字符(如et/):编码长度 2~4 位;
    • 低频字符(如~^):编码长度 10~13 位。

2. Huffman 编码流程

当需要传输未在字典中的字段名 / 值时,执行以下步骤:

  1. 标识编码方式:在字段的开头用 1 个 bit 标记 "是否使用 Huffman 编码"(1 = 使用,0 = 不使用);
  2. 字符转编码:将字符串的每个字符,替换为 Huffman 树中对应的二进制编码;
  3. 补位对齐:将二进制流补 0,对齐到字节(8 位);
  4. 添加结束符 :在末尾添加 Huffman 树的 "结束符"(0xFF,对应编码111111110),标识编码结束。

3. Huffman 解码流程

接收方收到编码后的字节流后:

  1. 解析标识位:判断是否为 Huffman 编码;
  2. 逐位匹配 Huffman 树:从根节点开始,按二进制位遍历树,直到匹配到叶子节点(得到对应字符);
  3. 处理结束符:遇到结束符时停止解码,忽略后续补位的 0。

三、HPACK 中整型数字的编码

HPACK 中,字典索引、字段长度等都需要用整型表示,为了压缩数字的字节数,HPACK 采用 **"前缀 + 扩展" 的变长编码 **,流程如下:

1. 选择前缀位数(N)

根据数字的大小,选择不同的前缀位数 N(N 可选 4、5、6、7、8):

  • 若数字≤2^N - 1:直接用 N 位表示;
  • 若数字 > 2^N - 1:先写 N 位的最大值(全 1),再用后续字节表示剩余值(每个字节的最高位是 "续传位":1 = 还有后续字节,0 = 结束)。

2. 编码示例(以 N=5 为例)

N=5 时,前缀最大能表示 31(2^5-1):

  • 编码数字10:直接用 5 位01010
  • 编码数字40
    1. 前缀写 5 位最大值11111
    2. 剩余值 = 40-31=9,转二进制1001
    3. 剩余值不足 7 位,补 0 成0001001,最高位加续传位(这里只有 1 个后续字节,续传位写 0)→ 字节为00001001
    4. 最终编码:11111 00001001(共 13 位)。

3. 解码示例

接收方收到11111 00001001(N=5):

  1. 前缀是11111,表示数字 > 31;
  2. 后续字节00001001,续传位是 0,取低 7 位0001001→值为 9;
  3. 最终数字 = 31+9=40。

四、HPACK 中头部名称与值的编码

HPACK 的头部字段(name: value)编码分为 3 种场景,核心是 "优先复用字典,减少明文传输":

场景 1:头部在静态 / 动态字典中(完全匹配)

直接用索引表示,编码格式:

  • 1 个 bit 标记 "索引字段"(0);
  • 后续是字典索引的整型编码(N=7)。

示例:传输:method: GET(静态字典索引 2)→ 编码为0 0000010(二进制)。

场景 2:头部名称在字典中,值不在(部分匹配)

用 "索引 + 值" 表示,编码格式:

  • 1 个 bit 标记 "文字字段,名称索引"(10);
  • 后续是名称的字典索引(N=6);
  • 再后续是值的编码(可选 Huffman 压缩)。

示例:传输Host: test.comHost在静态字典索引 7):

  1. 标记位10
  2. 名称索引 7→编码000111
  3. test.com用 Huffman 编码;
  4. 最终编码:10 000111 [Huffman编码后的test.com]

场景 3:头部名称和值都不在字典中(完全不匹配)

用 "明文名称 + 明文值" 表示,编码格式:

  • 1 个 bit 标记 "文字字段,名称文字"(11);
  • 后续是名称的长度编码(可选 Huffman)+ 名称的编码;
  • 再后续是值的长度编码(可选 Huffman)+ 值的编码。

示例:传输X-New-Header: abc(无字典匹配):

  1. 标记位11
  2. 名称X-New-Header:先编码长度(比如 12),再用 Huffman 编码字符串;
  3. abc:编码长度 3,再用 Huffman 编码;
  4. 最终编码:11 [名称长度+名称编码] [值长度+值编码]

0voice · GitHub

相关推荐
星火开发设计12 小时前
折半插入排序原理与C++实现详解
java·数据结构·c++·学习·算法·排序算法·知识
老鼠只爱大米12 小时前
LeetCode算法题详解 1:两数之和
算法·leetcode·面试题·两数之和·two sum
欧阳天羲12 小时前
ML工程师学习大纲
学习·算法·决策树
无序的浪12 小时前
HTTPS加密及工作过程
网络协议·http·https
AI爱好者202012 小时前
智能优化算法2025年新书推荐——《智能优化算法及其MATLAB实例(第4版)》
开发语言·算法·matlab
✧˖‹gσσ∂ иιghт›✧12 小时前
esp32 -s3 通过pdm麦克风实现tcp传输音频数据
网络协议·tcp/ip·音视频
北京耐用通信12 小时前
编码器连接新方案:耐达讯自动化CAN转PROFIBUS网关高效连接工业大脑
人工智能·科技·网络协议·自动化·信息与通信
LYFlied13 小时前
【每日算法】LeetCode215. 数组中的第K个最大元素
前端·算法
炽烈小老头13 小时前
【每天学习一点算法 2026/01/06】最小栈
学习·算法·leetcode
shughui13 小时前
OSI 七层 / TCP/IP 四层模型详解 + HTTP 与 WebSocket 接口分类:从协议本质 到 设计规范
websocket·网络协议·tcp/ip·http·设计规范