HTTP/2 对消息头采用 HPACK 进行压缩传输,能够节省消息头占用的网络的流量。如何理解 HPACK 压缩呢? 如果我们约定将常用的请求头的参数用一些特殊的编号来表示,比如 GET /index.html 用一个 1 来表示,POST /index.html 用 2 来表示。那么是不是可以节省很多字节? 为 HTTP/2 的专门量身打造的 HPACK 便是类似这样的思路延伸。它使用一份索引表来定义常用的 HTTP Header。把常用的 HTTP Header 存放在表里。请求的时候便只需要发送在表里的索引位置即可。例如 :method=GET 使用索引值 2 表示,:path=/index.html 使用索引值 5 表示。 具体这里的静态映射表请看附录的Table 1: Static Table Entries。

 

      比如我们想表达 请求的Header内容是:   GET /index.html   只要给服务端发送一个 Frame,该 Frame 的 Payload 部分存储 0x8285,Frame 的 Type 设置为 Header 类型。

      为什么是 0x8285,而不是 0x0205? 这是因为高位设置为 1 表示这个字节是一个完全索引值(key 和 value 都在索引中)。类似的,通过高位的标志位可以区分出这个字节是属于一个完全索引值,还是仅索引了 key,还是 key 和 value 都没有索引。因为索引表的大小的是有限的,它仅保存了一些常用的 HTTP Header,同时每次请求还可以在表的末尾动态追加新的 HTTP Header 缓存。动态部分称之为 Dynamic Table。Static Table 和 Dynamic Table 在一起组合成了索引表:

参考: http://io.upyun.com/2015/05/13/http2/ 

HPACK 不仅仅通过索引键值对来降低数据量,同时还会将字符串进行霍夫曼编码来压缩字符串大小。

以常用的 User-Agent 为例,它在静态表中的索引值是 58,它的值是不存在表中的,因为它的值是多变的。第一次请求的时候它的 key 用 58 表示,表示这是一个 User-Agent ,它的值部分会进行霍夫曼编码(如果编码后的字符串变更长了,则不采用霍夫曼编码)。服务端收到请求后,会将这个 User-Agent 添加到 Dynamic Table 缓存起来,分配一个新的索引值。客户端下一次请求时,假设上次请求User-Agent的在表中的索引位置是 62, 此时只需要发送 0xBE(同样的,高位置 1),便可以代表: User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36。其过程如下图所示:

 

HPACK: Header Compression for HTTP/2

图来自: http://chimera.labs.oreilly.com/books/1230000000545/ch12.html#HTTP2_PUSH

 

WireShark  可以看到具体的 Header 解密后的内容,如下图:

上图是用的 WireShark  Development Release (1.99.6) 看到的 Header frame 的内容。

https://www.wireshark.org/download.html 

 

Header  Frame 的数据格式

HTTP2 的 Header Frame 的数据区, 分下面几种格式,相关资料请参考:http://http2.github.io/http2-spec/compression.html#index.address.space

 

1、在 预定的头字段静态映射表 中已经有预定义的 Header Name 和 Header Value值

这时候的二进制数据格式如上图, 第一位固定为1, 后面7位为映射的索引值

An indexed header field starts with the '1' 1-bit pattern, followed by the index of the matching header field, represented as an integer with a 7-bit prefix

例子,

下图的 83 就是这样的,  83 的二进制字节标示  1000 0011 , 抹掉首位, 就是 3 , 对应的 静态映射表中 的 method: POST。

 

注意,不存在首位为0,但是后面可以在静态表中可以找到的情况。

 

2、 预定的头字段静态映射表中有 name,需要设置新值。

Literal Header Field with Incremental Indexing

这种情况下的数据格式为:

例子, 一个指定 path的Header, 

首字符 为 44 ,对应的二进制位   0100 0100   前两个字符为 01 ,  Index 为 4 , 即对应静态映射表中的 path 头。

第二个字符为 95  对应的二进制位 1001 0101 ,排除首字符对应的 Value Length 为 十进制的21。 即 算上 44, 一共23个字符来记录这个信息。

 

 

3、预定的头字段静态映射表中没有 name,需要设置新name和新值。

例子

40 的二进制是  0100 0000,  
02 的二进制是  0000 0010, 后七位的十进制值是 2

86 的二进制是  1000 0110  后7位的十进制值是 6

 

其他还有2种情况:

Literal Header Field without Indexing

  • Literal Header Field without Indexing — Indexed Name
  • Literal Header Field without Indexing — New Name

Literal Header Field Never Indexed

    • Literal Header Field Never Indexed — Indexed Name
    • Literal Header Field Never Indexed — New Name

请参考: http://http2.github.io/http2-spec/compression.html#index.address.space 

 

附录

HTTP2 中, 预定的头字段静态映射表如下。(Table 1: Static Table Entries)

 

 

 

 

参考资料:

【协议分析】HTTP2报文头及数据帧格式解析实例分析
http://blog.csdn.net/jiayanhui2877/article/details/45074315

HPACK: Header Compression for HTTP/2
http://http2.github.io/http2-spec/compression.html

HPACK: Header Compression for HTTP/2
https://httpwg.github.io/specs/rfc7541.html

HPACK - Header Compression for HTTP/2
draft-ietf-httpbis-header-compression-12
https://tools.ietf.org/html/draft-ietf-httpbis-header-compression-12#section-2.2

Chapter 12. HTTP/2

http://chimera.labs.oreilly.com/books/1230000000545/ch12.html#HTTP2_FRAMING

Huffman 编码压缩算法
http://coolshell.cn/articles/7459.html

为 HTTP/2 头压缩专门设计的 HPACK的更多相关文章

  1. WPF 用 DataTemplate 合并DataGrid列表列头<类似报表设计>及行头列头样式 - 学习

    WPF中 DataGrid 列头合并,类似于报表设计.效果图如下↓ 1.新建一个WPF项目WpfApplication1,新建一个窗体DataGridTest,前台代码如下: <Window x ...

  2. HTTPS、SPDY和HTTP/2的性能比较

    http://www.infoq.com/cn/news/2015/02/https-spdy-http2-comparison/ https://segmentfault.com/a/1190000 ...

  3. 再谈HTTP2性能提升之背后原理—HTTP2历史解剖

    即使千辛万苦,还是把网站升级到http2了,遇坑如<phpcms v9站http升级到https加http2遇到到坑>. 因为理论相比于 HTTP 1.x ,在同时兼容 HTTP/1.1 ...

  4. 2019前端面试系列——HTTP、浏览器面试题

    浏览器存储的方式有哪些 特性 cookie localStorage sessionStorage indexedDB 数据生命周期 一般由服务器生成,可以设置过期时间 除非被清理,否则一直存在 页面 ...

  5. 【HTTP】402- 深入理解http2.0协议,看这篇就够了!

    本文字数:3825字 预计阅读时间:20分钟 导读 http2.0是一种安全高效的下一代http传输协议.安全是因为http2.0建立在https协议的基础上,高效是因为它是通过二进制分帧来进行数据传 ...

  6. HTTP——https、http缓存、get与post、web安全、跨域

    HTTP诞生 1989年为知识共享而诞生的Web,提出了3项WWW构建技术: 标准通用标记语言设为HTML(HyperText Markup Language,超文本标记语言) 文档传输协议HTTP( ...

  7. http2.0 相对于 http1.1的优势

    1.http2.0完全是多路复用的,只需一个连接就可实现并行 可以将不同的请求夹杂在一起,只需一个连接就能加载一个页面. 2.可以让服务器将响应主动推动到客户端缓存中 当浏览器请求一个网页时,服务器除 ...

  8. 状态压缩dp相关

    状态压缩dp 状态压缩是设计dp状态的一种方式. 当普通的dp状态维数很多(或者说维数与输入数据有关),但每一维总 量很少是,可以将多维状态压缩为一维来记录. 这种题目最明显的特征就是: 都存在某一给 ...

  9. c++中头文件include规则浅析[译]

    英文原文地址 在开发大型的软件项目时,头文件需要得到恰当的管理,甚至在c中也会面临这种问题,当我们用c++开发时,头文件的管理会变得更复杂,更加耗费我们的时间去管理,下面我将讲一些包含规则来简化这个苦 ...

随机推荐

  1. MySQL数据库命令大全

    --数据库操作前的准备-- 创建数据库-- create database python_test_1 charset=utf8; -- 使用数据库-- use python_test_1; -- s ...

  2. 队列(循环队列)----C语言

    线性结构:有且只有一个根节点,且每个节点最多有一个直接前驱和一个直接后继的非空数据结构 非线性结构:不满足线性结构的数据结构 队列 队列一般分为两类:链式队列和顺序队列 链式队列---链式队列即用链表 ...

  3. Django安装(第一个项目)

    day60 从系统中选择已存在的解释器. 新建Django项目         命令行创建:             django-admin startproject mysite          ...

  4. MySQL(动态执行SQL)

    day61 防sql注入 delimiter \\ CREATE PROCEDURE p4 ( ), in arg int ) BEGIN set @xo = arg; PREPARE xxx FRO ...

  5. webpack快速入门——Json配置文件使用

    在实际工作中,我们的项目都会配置一个Json的文件或者说API文件,作为项目的配置文件. 有时候你也会从后台读取到一个json的文件,这节课就学习如何在webpack环境中使用Json. 如果你会we ...

  6. MySQL大量线程处于Opening tables的问题分析

    [作者] 王栋:携程技术保障中心数据库专家,对数据库疑难问题的排查和数据库自动化智能化运维工具的开发有强烈的兴趣. [问题描述] 最近有一台MySQL5.6.21的服务器,在应用发布后,并发线程Thr ...

  7. 【xsy1097】 拼图 构造题

    题目大意:请你使用n个图形拼成一个矩形.要求:①这每个图形都由1×1的小正方形组成,而且第i个图形由i个小正方形组成.②除了第1个和第2个图形以外,任意一个图形的所有小正方形,不都在一条直线上. 数据 ...

  8. 服务器集群的session管理

    应用服务器的高可用架构设计主要基于服务无状态这一特性,但是事实上,业务总是有状态的,单机情况下,Session可由部署在服务器上的web容器(如Jboss)管理.在使用负载均衡的集群环境中,由于负载均 ...

  9. JavaScript 函数的4种调用方法

    JavaScript 函数有 4 种调用方式. 每种方式的不同方式在于 this 的初始化. 作为一个函数调用 function myFunction(a, b) { return a * b; } ...

  10. Spring Security构建Rest服务-0702-个性化用户认证流程2

    登录成功后的处理AuthenticationSuccessHandler: 认证成功后,默认情况下spring security会继续访问之前访问的url,如果想自定义处理逻辑,用默认的就不行了.此时 ...