HTTP2详解

x33g5p2x  于2021-09-25 转载在 其他  
字(1.7k)|赞(0)|评价(0)|浏览(306)

HTTP2简介

HTTP2是对HTTP1.1的升级,对HTTP1.1性能问题进行了优化,主要从以下两个方面来优化:

1、头部压缩
HTTP1.1主要是对Body进行压缩,而头部却没有压缩。HTTP2通过HPACK算法对头部进行压缩,减少了传输时间。

2、队头阻塞
HTTP1.1使用的是TCP协议,并且为了节省资源,采用了长连接,长连接引入了队头阻塞的问题。HTTP2引入了流和帧,解决了HTTP层面上的队头阻塞。

HTTP2报文结构详解

1、二进制 替换 文本
HTTP1.1采用的是文本描述,也就是通过ASCII文本进行传输,采用文本描述的好处是调试程序方便,能够直接看出数据包中的数据情况。

而HTTP2使用的二进制来进行传输,用01串来描述数据,调试和查看数据的具体含义就不填方便了。但是这种二进制传输计算机解析方便,体积小,性能高。

举个例子,比如之前需要传递对应的文本值来表示对应的选择,而二进制通过二进制编码就能知道编码对应的选择,一个二进制编码对应着一个文本值。 一个二进制编码肯定比文本占用的空间小。

2、HTTP2将HTTP1中数据包分解为了帧
将HTTP1.1的数据包分为HEADERS帧DATA帧,属于是化整为零,为的就是多路复用,具体原理我们下边再说。

HTTP2连接过程

连接前言

当TCP三次握手成功后,客户端需要向服务器发送一个连接前言

连接前言是一个HTTP1.1报文,是一个ASCII文本,里面记录着一个magic字符串,当服务器接收到这个请求后,服务器就知道客户端想要使用HTTP2协议。

头部压缩

确定了HTTP2连接后,就开始准备发送HTTP2请求了。

首先就是发送HEADERS 帧,

HTTP1.1中对Body进行GZIP等压缩方式,但是对于头部却没有采取任何办法。

HTTP2采用了 HPACK 算法来压缩,HPACK 中客户端和服务器都要维护一个索引表。

如上图所示,索引表中维护了头部中Key-Value的对应关系和索引下标。

到时候,HTTP2请求中头部不用再发送Key-Value了,直接发送对应的索引下标就可以了。

上述的索引表是一个静态的表,记录着常用的头字段。HTTP的起始行中记录了Method、StatusCode等信息,也被记录到了索引表中。

有的HTTP2头部有着特殊的头部字段,所以HPACK又在静态表的尾部开始维护一个动态记录。当第一次发送索引表中不存在的Key-Value的时候,会使用实际数据发送,客户端和服务器对应的索引表会对其缓存,等到下一次发送的时候,就可以直接发送索引下标了。

所以说,HTTP2通过HPACK算法,将每次发送Key-Value替换成了发送一个下标,极大的减少了HTTP2头部的数据量,传输效率极大的提高了。

二进制帧

HTTP2将之前的head+body的一个数据包分为了 HEADER帧 和 若干个 DATA帧

格式如下图所示:

1、帧长度
帧的总长度,应用程序按照长度来读取

2、帧类型
HTTP2中有 数据帧、控制帧等类别,控制帧有着更高的传输优先权

3、标志位
8个bit,可以代表8个状态,比如END_HEADERS代表是否头数据传输结束、END_STREAM表示单方面传输数据结束

4、流标识符
帧属于哪个流,每个HTTP包传输都是一个虚拟流,通过流标识符才能将前后发送的帧重组为一个完整的数据包。

5、实际传输的数据

HTTP2发送过程

HTTP2利用帧+流的方式解决了HTTP1中的队头阻塞问题。

HTTP1中每个HTTP包复用一个TCP连接,每次只能等到前一个HTTP响应后才能发送后一个HTTP请求,如果前一个HTTP响应阻塞的话,后面的HTTP请求都会跟着阻塞,这就是队头阻塞问题。

HTTP2也是利用的长连接,多个HTTP请求复用一个TCP连接。
但是HTTP2将每个HTTP请求都看作一个流,将HTTP数据包分解为多个帧,包括HEADER帧DATA帧。每个帧都对应着一个流标识号。

多个HTTP请求之间的发送是乱序的,但是每个HTTP请求中的帧的发送是有序的。

虽然多个HTTP请求之间的发送请求是乱序的,但是可以基于流标识符来进行重组,一个流标识符对应着一个HTTP请求。

流标识符不能复用,是自动递增的,客户端使用的是奇数,服务器使用的偶数。

这就解决了队头阻塞问题。

相关文章