本文的目的是帮助读者快速理解 HTTP/2 的协议机制。一些协议细节方面的详细解释,会推荐相关文章链接供读者参考。
什么是 HTTP/2
HTTP/2 是 HTTP(超文本传输协议)的第二个主要版本,由 IETF 于 2015 年正式发表。多数主流浏览器已经在 2015 年底支持了该协议。
为什么要制定 HTTP/2
之所以制定 HTTP/2,是为了弥补 HTTP/1.1 存在的缺陷。HTTP/1.1 从 1999 年公布至今,已经开始不能使用互联网的发展了,主要体现在:
- 不允许浏览器异步接收服务器回应。这里“异步接收”指的是服务器返回回应的顺序与收到请求的顺序无关。也就是说,如果小内容的请求在大内容的请求之后发送,就必须先等待后者完全发送。浏览器为了减少这种等待,采取了开启多个 TCP 连接的方式,而这些连接除了最开始用来传输请求和回应数据外,绝大部分时间处于闲置状态,对浏览器主机和服务器来说都是不必要的负担。
- HTTP/1.1 是基于文本的协议,但默认没有对内容进行压缩。我们知道对文本进行压缩的话,能够将数据量减少到原来的 40% ~ 12%。减少数据量就能减少传输时间,同样加快页面加载。
HTTP/2 的特性
HTTP/2 的制定首先是为了解决上面所说的问题,而且为了给互联网留下更多的发展空间,HTTP/2 采取了完全不同的数据传输方式。
1. TCP 连接复用与帧传输:
首先,一个 TCP 连接可以用于传输多个 HTTP 请求。这点在 HTTP/1.1 上已经存在,但服务器只能按接收请求的顺序来发送回应,这种方式不足以提升数据传输效率。
HTTP/2 将一个 TCP 连接分成若干个流(Stream),每个流中可以传输若干个消息(Message),而且每个消息切分成多个帧(Frame)。也就是说,多个不同消息中的帧可以交替在同一个 TCP 连接中传输,内容较少或优先级较高的回应就可以更早的完成传输。
这里要注意的是,因为出现了帧这样的结构,HTTP/2 的传输内容格式就不再是纯文本的了,而是二进制格式。关于帧的格式细节,推荐阅读这篇文章。
2. HTTP 头压缩:
在 HTTP/1.1 中,标头(也叫 HTTP 头)是一个很大的传输负担,因为里面包含了各种协议配置,很多时候在一个 HTTP 回应传输当中,标头体积比回应内容本身的体积还大。
为了减少标头的负担,HTTP/2 采取了两个策略。首先,使用霍夫曼编码对标头内容进行压缩;其次,用数字索引来代替标头名称,这需要协议为浏览器和服务器约定一个标头字典。这两个策略组合起来叫做 HPACK 压缩。若想了解它的细节,推荐阅读这篇文章。
3. 流控制:
HTTP/2 为数据接收方提供了一种控制发送方发送速度的方式。之所以需要这种机制,是因为接收方可能需要暂时停止或减少数据接收。比如:1、用户看在线视频的时候暂停播放;2、用户上传文件的时候服务器很繁忙。这些情况下都需要发送方暂时停止发送数据。
流控制的基本原理是:
- 接收方告诉发送方自己为这个数据流准备了多大缓存(也叫窗口大小);
- 发送方每发送一个帧,都会从窗口大小减去对应的帧大小,如果窗口大小变为零,则不再发送帧;
- 接收方可以继续接收数据的话,要发送一个增加窗口大小的消息给发送方,这样发送方就可以继续发送了。
关于流量控制的细节,推荐阅读这篇文章。
4. 服务器端推送:
这里的服务器端推送不是指 WebSocket 那样的服务器端向浏览器主动发消息,而是指在 HTTP/2 中,服务器可以在收到浏览器请求后,主动向浏览器发送额外的资源。
例如一个网页引用了 CSS 和 JS 两个资源,那么浏览器为了加载这个页面就要发送三次请求。有了服务器端推送,当浏览器请求页面的时候,服务器就能够主动将 CSS 和 JS 推送给浏览器,省去两次请求的发送。
关于服务器端推送的细节,推荐阅读这篇文章。
总结
从上面的新特性一览中可以看出,帧结构和 TCP 连接复用是 HTTP/2 的核心特性,这样的设计为 HTTP/2 实现其他新特性提供了灵活可靠的基础。
另外,HTTP/2 的规定中只针对 HTTP 头做了压缩,那么传输内容会不会压缩呢?这个仍然遵守 HTTP 头中的规则,即如果 Content-Encoding
指定了压缩格式,那么帧当中的内容会按照这个压缩格式来传输。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。