HTTP2协议解析

2021-11-24  本文已影响0人  sunny4handsome

HTTP协议发展历史

  1. HTTP0.9

    1991年发布。该版本极其简单,只有一个命令GET,不支持请求头

  2. HTTP/1.0

    1996年5月发布。引入请求头和响应头;新增请求方法,如head/post

  3. HTTP1.1

    1997年1月发布。支持长连接;添加Content-Length字段;分块传输编码等

  4. SPDY

    2012年Google发布。HTTP2.0就是基于SPDY设计的,现在已经无人使用。添加多路复用(Multiplexing);header压缩(DEFLATE算法);服务端推送等

  5. HTTP2.0

    2015年发布。本文主要讲解内容,后文详细讨论。

  6. HTTP3.0

    2018年发布。尚未研究,不在本文讨论范围。

HTTP/2 的wiki介绍,可以看下定义和发展历史。RFC 7540 定义了 HTTP/2 的协议规范和细节, RFC 7541定义了头部压缩。如果有时间,最后就直接看RFC的文档。没有什么资料可以比官方文档写的更清楚。本文只是自已的归纳和整理。难免有些粗陋和错误,望评判指正。

一、HTTP2 解决什么问题

HTTP2的提出肯定是为了解决HTTP1.1已经存在的问题。所以HTTP1.1存在那些问题呢?

1.1 TCP连接数限制

因为并发的原因一个TCP连接在同一时刻可能发送一个http请求。所以为了更快的响应前端请求,浏览器会建立多个tcp连接,但是第一tcp连接数量是有限制的。现在的浏览器针对同一域名一般最多只能创建6~8个请求;第二创建tcp连接需要三次握手,增加耗时、cpu资源、增加网络拥堵的可能性。所以,缺点明显。

1.2 线头阻塞 (Head Of Line Blocking) 问题

每个 TCP 连接同时只能处理一个请求 - 响应,浏览器按 FIFO 原则处理请求,如果上一个响应没返回,后续请求 - 响应都会受阻。为了解决此问题,出现了 管线化 - pipelining 技术,但是管线化存在诸多问题,比如第一个响应慢还是会阻塞后续响应、服务器为了按序返回相应需要缓存多个响应占用更多资源、浏览器中途断连重试服务器可能得重新处理多个请求、还有必须客户端 - 代理 - 服务器都支持管线化。

1.3 Header 内容多

每次请求 Header不会变化太多,没有相应的压缩传输优化方案。特别是想cookie这种比较长的字段

对于HTTP1.1存在的这些问题,是有一定的优化方案的,比如用对个域名,文件合并等。但是这些毕竟比较麻烦,甚至无聊。

二、基本概念

这些概念的关系总结如下:

image.png

三、HTTP2特性有那些

需要强调的是HTTP/2 是对之前 HTTP 标准的扩展,而非替代。 HTTP 的应用语义不变,提供的功能不变,HTTP 方法、状态代码、URI和标头字段等这些核心概念也不变。
我们已经知道http1.x的报文格式由开始行首部行,实体主体三部分组成。HTTP2将开始行首部行封装成实体主体封装成。这里的是HTTP/2所有性能增强的核心。它定义了如何封装 HTTP 消息并在客户端与服务器之间传输。下图可以很好帮助大家理解http1.x和http2的关系。

image.png image.png

HTTP2特性包含一下几个方面

3.1 二进制分帧

帧是数据传输的最小单位,以二进制传输代替原本的明文传输,原本的报文消息被划分为更小的数据帧:


image.png

简言之,HTTP/2 将 HTTP 协议通信分解为二进制编码帧的交换,这些帧对应着特定数据流中的消息。所有这些都在一个 TCP 连接内复用。 这是 HTTP/2 协议所有其他功能和性能优化的基础。

3.1.1 HTTP2报文格式

所有帧都是一个固定的 9 字节头部 (payload 之前) 跟一个指定长度的负载 (payload),格式如下。


image.png

HTTP2共分为十种类型的帧:


image.png

HTTP2 帧和flags的可能组合示意图:

不同类型的帧可能对应的flags
表中x符号表示该类型的帧的flags可以取的值
下面看一些几种常见的帧完整结构

3.1.1.1 DATA 帧格式

DATA 帧的type为0x0。

DATA Frame Payload

Pad Length:? 表示此字段的出现时有条件的,需要设置相应标识 (set flag),指定 Padding 长度,存在则代表 PADDING flag 被设置
Data:传递的数据,其长度上限等于帧的 payload 长度减去其他出现的字段长度
Padding:填充字节,没有具体语义,发送时必须设为 0,作用是混淆报文长度,与 TLS 中 CBC 块加密类似

DATA 帧有如下标识 (flags):

3.1.1.2 HEADERS 帧格式

HEADERS Frame Payload

HEADERS 帧有以下标识 (flags):

3.1.1.3 SETTINGS 帧格式

一个 SETTINGS 帧的 payload 由零个或多个参数组成,每个参数的形式如下:

SETTINGS Format
在建立连接开始时双方都要发送 SETTINGS 帧以表明自己期许对方应做的配置,对方接收后同意配置参数便返回带有 ACK 标识的空 SETTINGS 帧表示确认,而且连接后任意时刻任意一方也都可能再发送 SETTINGS 帧调整,SETTINGS 帧中的参数会被最新接收到的参数覆盖
SETTINGS 帧作用于整个连接,而不是某个流,而且 SETTINGS 帧的 stream identifier 必须是 0x0,否则接收方会认为错误 (PROTOCOL_ERROR)。
SETTINGS 帧包含以下参数:

SETTINGS 帧有以下标识 (flags):

3.1.1.4 PRIORITY 帧格式

image.png
PRIORITY 帧可以在流的任何状态使用,Header帧中优先级是在打开的时候,注意区别。字段含义和header帧中的一样。PRIORITY只可作用于特定的流,不可作用于整个连接

3.1.1.5 RST_STREAM 帧格式

image.png

RST_STREAM帧用于立刻终止一个流

3.1.1.6 PUSH_PROMISE 帧格式

image.png

PUSH_PROMISE 帧有以下标识 (flags):

3.1.1.7 PING 帧格式

image.png

用于判断空闲连接是否可用。
PING 帧有以下标识 (flags):

3.1.1.8 GOAWAY 帧格式

image.png

3.1.1.9 WINDOW_UPDATE 帧格式

WINDOW_UPDATE用于流量控制,可作用于整个连接或者流


image.png

Window Size Increment 表示除了现有的流量控制窗口之外,发送端还可以传送的字节数。取值范围是 1 到 2^31 - 1 字节

3.1.1.10 CONTINUATION 帧格式

image.png

3.2 多路复用

简而言之:多个http请求可以共用同一个TCP连接

image.png

3.2.1 为什么http1.1不能实现多路复用

http1.1 是基于文本分割协议的。我们不知道一个请求什么时候结束,只能一直读取,直到出现空行(http请求结果标志)。所以就不能使用多路复用。要不然就不知道哪个消息是属于哪个请求了。但是HTTP2引入二进制分帧,用 stream id标识帧和请求的对应关系。

3.3 头部压缩

HTTP2使用的HPACK作为头部压缩算法。

image.png

可以清楚地看到 HTTP2 头部使用的也是键值对形式的值,而且 HTTP1 当中的请求行以及状态行也被分割成键值对,还有所有键都是小写,不同于 HTTP1。除此之外,还有一个包含静态索引表和动态索引表的索引空间,实际传输时会把头部键值表压缩,使用的算法即 HPACK,其原理就是匹配当前连接存在的索引空间,若某个键值已存在,则用相应的索引代替首部条目,比如 “:method: GET” 可以匹配到静态索引中的 index 2,传输时只需要传输一个包含 2 的字节即可;若索引空间中不存在,则用字符编码传输,字符编码可以选择哈夫曼编码,然后分情况判断是否需要存入动态索引表中。关于详细的压缩过程见参考文献10。

3.4 server push

服务端主动推送,如下图,page.html包含script.js和style.css资源文件。客户端只需要请求page.html,服务端发现page.html中包含资源文件会主动推送给客户端。减少客户端请求的次数。

image.png
所有服务器推送数据流都由 PUSH_PROMISE 帧发起,表明了服务器向客户端推送所述资源的意图,并且需要先于请求推送资源的响应数据传输。 这种传输顺序非常重要: 客户端需要了解服务器打算推送哪些资源,以免为这些资源创建重复请求。 满足此要求的最简单策略是先于父响应(即,DATA 帧)发送所有 PUSH_PROMISE 帧,其中包含所承诺资源的 HTTP 标头。

3.5 流量控制

多路复用的流会竞争 TCP 资源,进而导致流被阻塞。流控制机制确保同一连接上的流不会相互干扰。流量控制作用于单个流或整个连接。HTTP/2 通过使用 WINDOW_UPDATE 帧来提供流量控制。例如,客户端可能请求了一个具有较高优先级的大型视频流,但是用户已经暂停视频,客户端现在希望暂停或限制从服务器的传输,以免提取和缓冲不必要的数据。

3.6 资源优先级和依赖设置

客户端可以通过 HEADERS 帧的 PRIORITY 信息指定一个新建立流的优先级,其他期间也可以发送 PRIORITY 帧调整流优先级

每个流都可以显示地依赖另一个流,包含依赖关系表示优先将资源分配给指定的流(上层节点)而不是依赖流

参考文献

其中2,7是讲解的比较好的,可以重点参考

  1. HTTP/2协议“多路复用”实现原理
  2. HTTP2 详解
  3. Okhttp如何开启的Http2.0
  4. stakoverflow上关于HTTP2.0多路复用的一个比较好的解释
  5. HttpClient doesn't reuse TCP connection for both h2 and h2c connections
  6. HTTP/2 资料汇总
  7. HTTP/2 简介
  8. RFC 7540 Hypertext Transfer Protocol Version 2
  9. RFC 7541 HPACK: Header Compression for HTTP/2
  10. HTTP/2 头部压缩技术介绍
  11. 谈谈 HTTP/2 的协议协商机制
上一篇 下一篇

猜你喜欢

热点阅读