HTTP2 也就是超文本传输协议第 2 版,基于 TCP 连接的一个上层协议,允许在一个 TCP 连接上多路复用,支持优先级、流量控制、服务器推送、首部HPACK压缩、
保持了与 HTTP1 相同的基本语义,例如 方法语义 (GET PUST PUT DELETE 等)、状态码 (200 404 500 等)、URL 等等,相比来说做了如下的优化。
通过单个 TCP 连接支持多个通道;头部压缩,解析会更快、更小等等。
简介
HTTP2 传输的数据是二进制的,相比 HTTP1.X 的纯文本数据,二进制数据的传输体积更小,更易于解析,纯文本帧在解析的时候还要考虑处理空格、大小写、空行和换行等问题,而二进制帧就不存在这个问题。
在 HTTP2 中,有如下的三个概念,也就是:流 (Stream)、消息 (Message) 和帧 (Frame)。
- Stream 处于一个连接中的虚拟双向二进制数据流,通过一个唯一的整数进行标识,可以包含一个或者多个 Message 。
- Message 一个完整的请求或者响应,比如请求、响应等,由一个或多个 Frame 组成。
- Frame HTTP2 通讯最小单位,每个帧包含帧首部帧,表示当前帧所属的流,承载着特定类型的数据,如 HTTP 首部、负荷等。
每个 HTTP2 连接上传输的帧都关联到一个 “流”,这是一个逻辑上的概念,作为一个独立的双向帧序列,用于在客户端和服务器端之间进行通讯。
可以包含多个并发的流,任何一端都可以交错地插入帧。
优先级
优先级是为了设置对端在并发的多个流之间分配资源的方式,尤其是当发送容量有限时,可以选择优先发送的流。
流之间可以相互依赖,只有当所依赖的流完成后,才会再处理当前流,同时每个依赖后都跟着一个权重 (weight),用来确定依赖于相同的流的可分配可用资源的相对比例。
简介
每个资源都获取一个 Stream ID 来标识连接上的资源,有三个参数用于定义资源优先级:
- 流依赖 Stream Dependencies。只有当依赖的流数据发送完成之后,才会发送当前流,默认使用共享的 Stream0 。
- 权重 Weight。分配 1~256 之间的数字,标识在多个数据流共享连接时分配给此数据流的带宽量,按照权重比例分配。
- 独占位 Exclusive Bit。用来表示在不与任何其它数据流共享带宽的情况下下载。
浏览器不一定同时知道所有资源,因此服务器能够在新请求到达时确定请求的优先级也很关键。
流依赖
注意,因为流可以在不同状态之间切换,如果被依赖的流不在当前依赖树中 (如流的状态为 idle ),被依赖的流会使用一个默认优先级。
当依赖一个流时,该流会添加进父级的依赖关系中,共享相同父级的依赖流不会相对于彼此进行排序,比如 B 和 C 依赖 A,新添加一个依赖流 D,BCD 的顺序是不固定的。
A A
/ \ ==> /|\
B C B D C
可以通过独占标识 (exclusive) 插入一个新层级,这会导致该流成为父级的唯一依赖流,而其它依赖流变为其子级。例如插入一个新带有独占标识的依赖流 E 。
A
A |
/|\ ==> E
B D C /|\
B D C
在依赖关系树中,只有当一个流依赖的所有流被关闭或者无法继续时,这个流才应该被分配资源。
权重
相同父级的依赖流按权重比例分配资源,比如 B 和 C 都依赖于 A ,其权重值分别为 4 和 12 ,那么理论上 B 能分配的资源只有 C 的三分之一。
优先级调整
在正常使用流的过程中,可以通过 PRIORITY 帧来调整流优先级。
如果父级重新设置了优先级,则依赖流会随其父级流一起移动;若调整优先级的流带有独占标识,会导致新的父流的所有子级依赖于这个流
如果一个流 A 调整为依赖自己的一个子级 (包括孙子) D,则首先将子级 D 移至 A 的父级之下(即同一层),然后再移动 A 的整棵子树,移动的依赖关系保持其权重。
X X X X
| / \ | |
A D A D D
/ \ / / \ / \ |
B C ==> F B C ==> F A OR A
/ \ | / \ /|\
D E E B C B C F
| | |
F E E
(intermediate) (non-exclusive) (exclusive)
如上示例将 A 调整依赖 D ,调整的步骤为:A) 现将 D 移至 X 之下;B) 把 A 调整为 D 的子树;C) 如果 A 调整时带有独占标识根据第一点 F 也归为 A 子级。
优先级管理
当依赖树中的某个节点被删除,那么子级会调整为了依赖父级,权重会根据被删除节点和自身的权重重新计算。
X(v:1.0) X(v:1.0)
/ \ /|\
/ \ / | \
*A B ==> / | \
(w:16) (w:16) / | \
/ \ C *D B
/ \ (w:8)(w:8)(w:16)
C *D
(w:16) (w:16)
R(C)=16/(16+16)=1/2 ==> R(C)=8/(8+16)=1/3
如果上述 A D 不可用,那么图中的 B C 就会各占一半的资源,当 A 被移除后,C 和 D 会按照权重分配 A 的权重,也就是都变成了 8 ,此时 D 仍然不可用,那么 A 会占用 1/3 的资源。
帧 Frame
HTTP2 的最小数据单位是帧,所有帧以 9 字节的帧头并跟着 0~16,383
字节的数据。
+-----------------------------------------------+
| Length (24) |
+---------------+---------------+---------------+
| Type (8) | Flags (8) |
+-+-------------+---------------+-------------------------------+
|R| Stream Identifier (31) |
+=+=============================================================+
| Frame Payload (0...) ...
+---------------------------------------------------------------+
参考
- HTTP2 的协议,也就是 RFC7540 的详细介绍 Hypertext Transfer Protocol Version 2 。
- 关于 HTTP2 的所有版本实现可以参考 HTTP2 Implementations 。
- High Performance Browser Networking HTTP2 。