http 2.0协议解析

1 协议概述

Http2协议是一个二进制协议,二进制更易于frame(帧 数据包)的实现,Http2有十个不同frame定义,其中两个最基础的对应于HTTP 1.1的是Data数据和HEADE头部,其后将描述。

frame是包含几个部分:类型Type, 长度Length, 标记Flags, 流标识Stream和frame payload有效载荷。

流标识是描述二进制frame的格式,使得每个frame能够基于http2发送,与流标识联系的是一个流,每个流是一个逻辑联系,一个独立的双向的frame存在于客户端和服务器端之间的http2连接中。一个http2连接上可包含多个并发打开的流,这个并发流的数量能够由客户端设置,这些流可能是打散了通过物理连接传输。

2 差别

http1.x诞生的时候是明文协议,其格式由三部分组成:start line(request line或者status line),header,body。要识别这3部分就要做协议解析,http1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合。基于这种考虑http2.0的协议解析决定采用二进制格式,实现方便且健壮。

http2.0用binary格式定义了一个一个的frame,和http1.x的格式对比如下图:

3 改进

3.1 多路复用

在 HTTP/1.1 协议中「浏览器客户端在同一时间,针对同一域名下的请求有一定数量限制。超过限制数目的请求会被阻塞」,总的来说http1.1里面也有多路复用这种概念。但是一直没有被推广,因为毕竟是单线程的,请求顺序受影响,请求返回的时候通道顺序受影响,比如第一个请求响应被阻塞了,那么后续的也会被阻塞。这就是为什么没有推广的原因,具体如下图所示: 可以看到,要么是串行,一个请求完成后再发另一个请求,要么是可以并发,但请求结果的返回过程必须是顺序的,第一个响应完成后,才能响应第二个,即使第二个先处理完成,也要等待第一个,就产生了阻塞

http2.0 的处理方式

http2.0也是单线程,但是是基于并行流的方式,只要有了请求结果数据,可以立即返回,不关心顺序问题,因为数据都被组装成了一个个的frame帧,frame中记录了自己所属数据流的ID,客户端把frame都接收到以后,根据数据流ID再进行组装即可

3.2 文本协议改成二进制协议

3.3 头部压缩

http1.x的header由于cookie和user agent很容易膨胀,而且每次都要重复发送。http2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。高效的压缩算法可以很大的压缩header,减少发送包的数量从而降低延迟。

3.4 Server Push

知乎里面有篇文章很详细链接,针对于Server Push来说,对于移动端这种情况,我个人感觉是比较鸡肋的,毕竟android端网络不像pc这么稳定。但是针对于pc端来说,这个是相当强大的功能,

3.5 更安全的SSL

HTTP2.0使用了tls的拓展ALPN来做协议升级,除此之外加密这块还有一个改动,HTTP2.0对tls的安全性做了近一步加强,通过黑名单机制禁用了几百种不再安全的加密算法,一些加密算法可能还在被继续使用。如果在ssl协商过程当中,客户端和server的cipher suite没有交集,直接就会导致协商失败,从而请求失败。在server端部署http2.0的时候要特别注意这一点。

3.6 二进制分帧

Frame 是 HTTP/2 二进制格式的基础,基本可以把它理解为它 TCP 里面的数据包一样。HTTP/2 之所以能够有如此多的新特性,正是因为底层数据格式的改变。 Frame 的基本格式如下(图中的数字表示所占位数,内容摘自 http2-draft-17):

+-----------------------------------------------+
|                 Length (24)                   |
+---------------+---------------+---------------+
|   Type (8)    |   Flags (8)   |
+-+-------------+---------------+-------------------+
|R|                 Stream Identifier (31)          |
+=+=================================================+
|                   Frame Payload (0...)        ...
+---------------------------------------------------+

Length: 表示 Frame Payload 部分的长度,另外 Frame Header 的长度是固定的 9 字节(Length + Type + Flags + R + Stream Identifier = 72 bit)。

Type: 区分这个 Frame Payload 存储的数据是属于 HTTP Header 还是 HTTP Body;另外 HTTP/2 新定义了一些其他的 Frame Type,例如,这个字段为 0 时,表示 DATA 类型(即 HTTP/1.x 里的 Body 部分数据)

Flags: 共 8 位, 每位都起标记作用。每种不同的 Frame Type 都有不同的 Frame Flags。例如发送最后一个 DATA 类型的 Frame 时,就会将 Flags 最后一位设置 1(flags &= 0x01),表示 END_STREAM,说明这个 Frame 是流的最后一个数据包。

R: 保留位。

Stream Identifier: 流 ID,当客户端和服务端建立 TCP 链接时,就会先发送一个 Stream ID = 0 的流,用来做些初始化工作。之后客户端和服务端从 1 开始发送请求/响应。

Frame 由 Frame Header 和 Frame Payload 两部分组成。不论是原来的 HTTP Header 还是 HTTP Body,在 HTTP/2 中,都将这些数据存储到 Frame Payload,组成一个个 Frame,再发送响应/请求。通过 Frame Header 中的 Type 区分这个 Frame 的类型。由此可见语义并没有太大变化,而是数据的格式变成二进制的 Frame。二者的转换和关系如下图:

results matching ""

    No results matching ""