什么是HTTP/2

370 阅读6分钟

HTTP 是一个计算机网络的应用层协议,目前通用的是 1.1 版本,2 是最新版本。

我们首先要知道的是,所谓协议,就是双方都遵守的规范,这里的双方就是指客户端服务器。协议只是一份文本材料,它不是一个可以运行的软件。协议想要生效,必须得到双方的支持,也就是实现

要理解协议和实现,可以通过一个例子来说明。比如你想生产一种新款的水杯,于是写了一份该水杯的规格文档,文档里规定了水杯的尺寸、材质、表面的涂层和图案等。这份规格文档就是协议,然后你拿着文档去找生产水杯的工厂,让工厂按照规格文档给你生产出实际的杯子,这个杯子就是具体的实现。

由上述例子可知,具体的实现是协议得以存在的土壤。客户端的实现一般是浏览器,比如常用的 Chrome 浏览器,服务端的实现就是 Web 服务器,比如 Apache。

任何事物的发展都有一个过程和原因,HTTP/1.1 之前的版本这里就不赘述了。HTTP/1.1 在 1997 正式发布之后,过了 10 多年,在 2009 年的时候,Google 发明了一个称为 SPDY 的协议,并企图用它来代替 HTTP/1.1。为什么 Google 放着好好的 HTTP/1.1 协议不用,要搞自己的协议呢?因为基于 HTTP/1.1 协议的客户端和服务器,在传输文件时太慢。SPDY 读作 Speedy,目标就是要比 HTTP/1.1 快 50% 以上。SPDY 既然这么好,当然要纳入标准了。于是从 2012 年开始,制定 HTTP 规范的工作小组就开始着手制定 HTTP/2 的规范,直到 2015 年,HTTP/2 的标准规范发布了。

相比 HTTP1.1,HTTP2 主要有以下几方面的不同。

  1. 头部压缩。
  2. server push。
  3. 二进制格式传输。
  4. 多路复用。

头部压缩

HTTP 请求的头部字段中,有很多是重复的、甚至是没有必要的,但是每次请求还是会带上,比如:CookieUser-AgentHostAccept。这些字段在同一个网络会话中通常是不会改变的,但是被重复发送。响应头也同样如此。特别是对一些比较小的请求来说,头部字段可能占整个网络报文非常大的比重。HTTP/1.1 支持对请求体进行压缩,但不支持对请求头压缩。HTTP/2 弥补了这个短板。

server push

所谓 server push,就是服务器可以在客户端没有请求的情况下,主动把静态资源发给它。在 HTTP/1.1 里,请求一个页面,首先要请求 HTML 文件,然后根据 HTML 的内容再依次请求 CSS 文件,JavaScript 文件,图片,字体文件等静态资源,这会消耗大量的时间。通过 HTTP/2 的 server push 功能,可以在首次响应 HTML 文件的时候,把响应的所有其他静态资源并行的发送给客户端,这样就大大节省了网络传输的时间,页面展示的速度也加快了。

二进制格式传输

HTTP/1.1 传输的报文是基于文本的,对人友好,但对机器不友好。文本本身也不是一种结构化的信息,对它解析也比较低效;相对来说,HTTP/2 传输的报文是二进制的,对人不友好,但对机器友好,它是一种结构化的信息。HTTP/2 把一对独立的 HTTP 请求/响应抽象成为一个 Stream,一个 Stream 由若干个 frame 组成。每个 frame 由若干个字节组成,并且对字节或字节组进行了分区,赋予他们不同的语义。比如前 3 个字节定义了 frame paylad 的字节长度,第 4 个字节定义了该 frame 的类型,还有 4 个字节用来定义 Stream 的唯一标识。当然主要的字节数用来承载实际要传输的信息,也就是 payload。通过这种方式,每个请求/响应都由若干个 frame 组成,每个 frame 对应了一个唯一的 Stream,并且记录了它在该 Stream 对对应的次序,方便在客户端/服务器收到全部 frame 后进行报文的拼装。

多路复用

正是因为上述的报文 frame 化,才使得多路复用成为可能,每个 TCP 连接可以同时并行传输多个 Stream,大大提高了 TCP 连接的传输效率。

HTTP/2 的网络消息只能以 HTTPS 的形式来传输,有 2 个原因

  1. 使用 HTTPS 来传输,可以向后兼容目前互联网上的基础设施。因为 HTTPS 是加密的,可以隐藏 HTTP/2 frame 的信息,互联网上的中间件、代理服务器等可以直接进行转发。如果通过 HTTP 来传输的话,互联网中的服务器在查阅网络包中的信息时,会无法理解 HTTP/2 的二进制数据格式。
  2. 众多浏览器供应商倾向于使用 HTTPS 来请求网页,因为它更安全,一些新的功能也只会支持 HTTPS,对 HTTP,浏览器的态度是要废弃它,尽量不支持它。所以新的 HTTP/2 协议自然也仅允许在 HTTPS 下支持。

要支持 HTTP/2,服务器和客户端都必须支持,包括中间的代理服务器等也必须支持。

  1. 客户端的支持比较好,主流浏览器基本都支持,兼容性没什么问题(只有 IE11 在 Windows10 上部分支持)
  2. 服务端的支持要看情况,相对比较复杂一些。因为支持服务器使用的操作系统大多是 Linux,而用到的 web server 大多是系统级软件(比如 Apache),这些 web server 基本都会由 Linux 操作系统内置。如果服务器的操作系统版本比较旧一点,自带的 web server 就不一定支持 HTTP/2。另外一方面,要实现 HTTP/2,内部一般要依赖 OpenSSL 库来支持 HTTPS(因为 HTTP/2 一定要通过 HTTPS 才能运行),而 HTTP/2 对 OpenSSL 的版本也是有要求的(必须要能支持 ALPN:Application Layer Protocol Negotiation),所以如果服务器要能完整支持 HTTP/2,可能需要升级上述这些软件,甚至是升级操作系统。但是一个稳定运行的服务器,做这样的升级是有风险的,而且可能很麻烦(这些系统级软件往往牵一发动全身,升级后可能会影响其他的服务)。

那如果不升级服务器相关基础设施,能否有其他方式支持 HTTP/2 呢?其实我们可以在服务器之前增加另一套基础设施(软件或服务),由它们作为中间层来处理 HTTP/2 请求,服务器本身还是只支持 HTTP/1.1。这种策略具体有如下两种实现方式:

  1. 反向代理服务器:比如 nginx,nginx 支持 HTTP/2,客户端也支持 HTTP/2,那它们俩就能互相沟通,nginx 再把 HTTP/2 消息翻译成 HTTP/1.1,由它跟最终的服务器沟通。
  2. CDN