Skip to main content

HTTP 版本特性

HTTP/2 相比于 HTTP/1.1 大幅度提高了网页的性能,但存在兼容性及如何优雅降级的问题。

虽然 HTTP/2 提高了网页的性能,但不代表它是完美的,HTTP/3 就是为了解决 HTTP/2 存在的一些问题而推出。

一、HTTP/0.9

  • 只支持 GET 请求方式;
  • 没有请求头;
  • 服务端响应后立即关闭 TCP 连接。

HTTP 最早版本的是 1991 年发布的 0.9 版,该版本极其简单,只有一个命令 GET。

GET /index.html

上面命令表示,TCP 连接(connection)建立后,客户端向服务器请求(request)网页 index.html

协议规定,服务器只能回应 HTML 格式的字符串,不能回应其它格式。

<html>
<body>Hello World</body>
</html>

服务器发送完毕就关闭 TCP 连接。

二、HTTP/1.0

  • 请求方法新增 POST 和 HEAD;
  • 扩充了传输内容格式(图片、音视频资源、二进制等)
  • 添加了请求头和响应头;
  • ...

1996 年 5 月,HTTP/1.0 版本发布,内容大幅度增加。

首先,除了 GET 方法,还引入了 POST 和 HEAD 方法,丰富了浏览器与服务器的互动手段。

其次,任何格式的内容都可以发送。这使得互联网不仅可以传输文字,还能传输图像、视频、二进制文件。

再次,HTTP 请求和回应的格式也变了,除了数据部分,每次通信都必须包括头信息(HTTP header),用来描述一些元数据。

其他的新增功能还包括状态码(status code)、多字符集支持、多部分发送(multi-part type)、权限(authorization)、缓存(cache)、内容编码(content encoding)等。

三、HTTP/1.1

  • 请求方法新增 PUT、DELETE、OPTIONS、CONNECT 和 TRACE;
  • 引入持久连接;
  • 引入管线化;
  • 新增 Host 字段;
  • 新增 cache-control 字段;
  • 支持断点传输。

1997 年 1 月,HTTP/1.1 版本发布。它进一步完善了 HTTP 协议,一直流行到现在。

1、新增请求方法

HTTP/1.1 的请求方法新增了 PUTDELETEOPTIONSTRACECONNECT

2、引入持久连接

HTTP/1.1 的最大变化,就是引入了持久连接(persistent connection),即 TCP 连接默认不关闭,可以被多个请求复用,不用声明 Connection: keep-alive。

客户端和服务器发现对方一段时间没有活动,就可以主动关闭连接。不过,规范的做法是,客户端在最后一个请求时,发送 Connection: close,明确要求服务器关闭 TCP 连接。

Connection: close

目前,对于同一个域名,大多数浏览器允许同时建立 6 个持久连接。

3、引入管线化

HTTP/1.1 还引入了管线化(pipelining),即在同一个 TCP 连接里面,客户端可以同时发送多个请求。这样就进一步改进了 HTTP 协议的效率。

4、新增 Host 字段

HTTP/1.1 客户端请求的头信息新增了 Host 字段,用来指定服务器的域名。

Host: www.example.com

有了 Host 字段,就可以将请求发往同一台服务器上的不同网站,为虚拟主机的兴起打下了基础。

5、新增 cache-control 字段

当浏览器请求资源时,先看是否有缓存的资源,如果有缓存,直接取,不会再发请求,如果没有缓存,则发送请求。

通过设置字段 cache-control 来控制缓存。

6、支持断点传输

在上传/下载资源时,如果资源过大,将其分割为多个部分,分别上传/下载,如果遇到网络故障,可以从已经上传/下载好的地方继续请求,不用从头开始,提高效率。

7、HTTP/1.1 的缺陷

  • 队头阻塞导致的高延迟;
  • 无状态特性带来的巨大 HTTP 头部;
  • 明文传输带来的不安全性;
  • 不支持服务器推送消息。

7-1、队头阻塞导致的高延迟

虽然 HTTP/1.1 允许复用 TCP 连接,但同一个 TCP 连接中所有的数据通信是按次序进行的。服务器只有处理完一个回应,才会进行下一个回应。要是前面的回应特别慢,后面就会有许多请求排队等着。这称为"队头阻塞"(Head-of-line blocking)。

为了避免这个问题,只有两种方法:

  • 减少请求数;
  • 同时多开持久连接。

这导致了很多额外的网页优化工作,比如引入雪碧图、将小图内联到 CSS、使用多个域名等等,例如:

/* 将小图内联到 CSS */
.icon1 {
background: url(data:image/png;base64,<data>) no-repeat;
}
.icon2 {
background: url(data:image/png;base64,<data>) no-repeat;
}

7-2、无状态特性带来的巨大 HTTP 头部

由于报文 Header 一般会携带 "User Agent"、"Cookie"、"Accept"、"Server" 等许多固定的头字段(如下图),多达几百字节甚至上千字节,但 Body 却经常只有几十字节(比如 GET 请求、204/301/304 响应),成了不折不扣的“大头儿子”。Header 里携带的内容过大,在一定程度上增加了传输的成本。更要命的是,成千上万的请求响应报文里有很多字段值都是重复的,非常浪费。

7-3、明文传输带来的不安全性

HTTP/1.1 在传输数据时,所有传输的内容都是明文,客户端和服务器端都无法验证对方的身份,这在一定程度上无法保证数据的安全性。

7-4、不支持服务器推送消息

客户端想要获取更新需要通过轮询的方式,十分浪费带宽,占用资源。

WebSocket 是 HTML5 新增的协议,它在浏览器和服务器之间建立一个不受限的双向通信的通道,比如说,服务器可以在任意时刻发送消息给浏览器。

四、SPDY 协议

2009 年,谷歌公开了自行研发的 SPDY 协议,主要解决 HTTP/1.1 效率不高的问题。

SPDY 位于 HTTP 之下,TCP 和 SSL之上,这样可以轻松兼容老版本的 HTTP 协议(将 HTTP/1.x 的内容封装成一种新的 frame 格式),同时可以使用已有的 SSL 功能。

这个协议在 Chrome 浏览器上证明可行以后,就被当作 HTTP/2 的基础,主要特性都在 HTTP/2 之中得到继承。

五、HTTP/2

  • 二进制传输:HTTP 2 头信息和数据体都是二进制;
  • Header 压缩:HTTP 2 使用 HPACK 算法对 header 的数据进行压缩;
  • 多路复用:在共享 TCP 的基础上同时发送请求和响应;
  • 服务器推送:服务器可以额外的向客户端推送资源,而无需客户端明确的请求。

2015年,HTTP/2 发布。它不叫 HTTP/2.0,是因为标准委员会不打算再发布子版本了,下一个新版本将是 HTTP/3。

HTTP/2 基于 SPDY,专注于性能,最大的一个目标是在用户和网站间只用一个连接(connection),使用 HTTP/2 能带来 20%~60% 的效率提升。

HTTP/2 的新特性如下:

1、二进制传输

HTTP/2 传输数据量大幅减少,主要原因是以二进制方式传输和 Header 压缩。

HTTP/2 采用二进制格式传输数据,而非 HTTP/1.x 里纯文本形式的报文,解析起来更高效。而且将请求和响应数据分割为更小的帧,并且采用二进制编码,多个帧之间可以乱序发送,根据帧首部的流标识可以重新组装。

2、Header 压缩

无论是 HTTP/1.1 还是 HTTP/2,它们都有请求头和响应头,这是浏览器和服务器的通信语言。

HTTP/2 引入了头信息压缩机制(header compression),对请求头和响应头进行了压缩,使得传输效率得到大幅提升。

3、多路复用

在 HTTP/2 中引入了多路复用的技术,一个域名只使用一个 TCP 长连接来传输数据,这样整个页面资源的下载过程只需要一次慢启动,同时也解决了浏览器限制同一个域名下的请求数量的问题,更容易实现全速传输。

举例来说,在一个 TCP 连接里面,服务器同时收到了 A 请求和 B 请求,于是先回应 A 请求,结果发现处理过程非常耗时,于是就发送 A 请求已经处理好的部分,接着回应 B 请求,完成后,再发送 A 请求剩下的部分。

上面是 HTTP/2 最核心的多路复用机制,可以看到每个请求都有一个对应的 ID,如 stream1 表示 index.html 的请求,stream2 表示 foo.css 的请求。这是因为 HTTP/2 的数据包是不按顺序发送的,同一个连接里面连续的数据包,可能属于不同的回应。因此,必须要对数据包做标记,指出它属于哪个回应。

HTTP/2 将每个请求或回应的所有数据包,称为一个数据流(stream)。每个数据流都有一个独一无二的编号。数据包发送的时候,都必须标记数据流 ID,用来区分它属于哪个数据流。

服务器端接收到这些请求后,会根据自己的喜好来决定优先返回哪些内容,比如服务器可能早就缓存好了 index.htmlbar.js 的响应头信息,那么当接收到请求的时候就可以立即把 index.htmlbar.js 的响应头信息返回给浏览器,然后再将 index.htmlbar.js 的响应体数据返回给浏览器。

之所以可以随意发送,是因为每份数据都有对应的 ID,浏览器接收到之后,会筛选出相同 ID 的内容,将其拼接为完整的 HTTP 响应数据。

客户端还可以指定数据流的优先级。优先级越高,服务器就会越早回应。

HTTP/2 使用了多路复用技术,可以将请求分成一帧一帧的数据去传输,这样带来了一个额外的好处,就是当收到一个优先级高的请求时,比如接收到 JavaScript 或者 CSS 关键资源的请求,服务器可以暂停之前的请求来优先处理关键资源的请求。

4、服务器推送

HTTP/2 允许服务器未经请求,主动向客户端发送资源,这叫做服务器推送(server push)。

场景:当用户请求一个 HTML 页面之后,服务器知道该 HTML 页面会引用几个重要的 JavaScript 文件和 CSS 文件,那么在接收到 HTML 请求之后,附带将要使用的 CSS 文件和 JavaScript 文件一并发送给浏览器,这样当浏览器解析完 HTML 文件之后,就能直接拿到需要的 CSS 文件和 JavaScript 文件,这对首次打开页面的速度起到了至关重要的作用。

另外,服务端可以主动推送,客户端也有权利选择是否接收。如果服务端推送的资源已经被浏览器缓存过,浏览器可以通过发送 RST_STREAM 帧来拒收。主动推送也遵守同源策略,换句话说,服务器不能随便将第三方资源推送给客户端,而必须是经过双方确认才行。

5、HTTP/2 的缺陷

  • TCP 以及 TCP+TLS 建立连接的延时;
  • TCP 的队头阻塞并没有彻底解决。

5-1、TCP 以及 TCP+TLS 建立连接的延时

HTTP/2 使用 TCP 协议来传输,如果使用 HTTPS 则需要使用 TLS 协议进行安全传输,而使用 TLS 也需要一个握手过程,这样就需要有两个握手延迟过程:

  1. 建立 TCP 连接时需要和服务器进行三次握手来确认连接成功,也就是说要消耗完 1.5 个 RTT 之后才进行数据传输。
  2. 进行 TLS 连接,TLS 的两个版本 TLS1.2/TLS1.3 建立连接所花的时间不同,大致需要 1~2 个RTT。

总之,在传输数据之前,需要花掉 3~4 个 RTT。

5-2、TCP 的队头阻塞并没有彻底解决

由于 HTTP/2 中多个请求跑在一个 TCP 管道中,当出现丢包时,TCP 为了保证可靠传输,会进行丢包重传,因此 HTTP/2 出现丢包时整个 TCP 都要开始等待重传,会阻塞该 TCP 连接中的所有请求。

而对于 HTTP/1.1 来说,可以开启多个 TCP 连接,出现这种情况反到只会影响其中一个连接,剩余的 TCP 连接还可以正常传输数据。

六、HTTP/3

Google 在推 SPDY 时就意识到上面 HTTP/2 的这些问题(由 TCP 协议导致),由于 TCP 协议僵化,几乎不可能通过修改 TCP 协议自身来解决这些问题。于是 Google 另起炉灶搞了一个基于 UDP 协议的 QUIC 协议,让 HTTP 跑在 QUIC 上而非 TCP 上。

这个 HTTP over QUIC 就是 HTTP 协议的下一个大版本,HTTP/3,它在 HTTP/2 的基础上又实现了质的飞跃,真正“完美”地解决了“队头阻塞”问题。

QUIC 虽然基于 UDP,但是在原本的基础上新增了很多功能,例如:

  • 保证数据可靠性传输;
  • 实现了快速握手功能;
  • 集成了 TLS 加密功能;
  • 彻底解决 TCP 中队头阻塞的问题。

1、保证数据可靠性传输

虽然 UDP 不提供可靠性的传输,但 QUIC 在 UDP 的基础之上增加了一层来保证数据可靠性传输。它提供了数据包重传、拥塞控制以及其他一些 TCP 中存在的特性。

2、实现了快速握手功能

QUIC 基于 UDP,而 UDP 是“无连接”的,不需要“握手”和“挥手”,所以可以用最快的速度来发送和接收数据。

3、集成了 TLS 加密功能

QUIC 目前使用的是 TLS1.3,相较于早期版本 TLS1.3 有更多的优点,其中最重要的一点是减少了握手所花费的 RTT 个数。

4、彻底解决队头阻塞的问题

QUIC 也实现了 HTTP/2 中的多路复用功能,但和 TCP 不同,QUIC 实现了在同一物理连接上可以有多个独立的逻辑数据流,实现了数据流的单独传输,解决了 TCP 中队头阻塞的问题。

七、总结

版本特性
HTTP/0.9
  • 只支持 GET 请求方式;
  • 没有请求头;
  • 服务端响应后立即关闭 TCP 连接。
HTTP/1.0
  • 请求方法新增 POST 和 HEAD;
  • 扩充了传输内容格式(图片、音视频资源、二进制等)
  • 添加了请求头和响应头;
HTTP/1.1
  • 请求方法新增 PUT、DELETE、OPTIONS、CONNECT 和 TRACE;
  • 引入持久连接;
  • 引入管线化;
  • 新增 Host 字段;
  • 新增 cache-control 字段;
  • 支持断点传输。
HTTP/2
  • 二进制传输;
  • Header 压缩;
  • 多路复用;
  • 服务器推送。
HTTP/3
  • 保证数据可靠性;
  • 快速握手;
  • 集成 TLS 加密;
  • 解决队头阻塞。