一文串联 HTTP / [ 0.9 | 1.0 | 1.1 | 2 | 3 ]

共 6497字,需浏览 13分钟

 ·

2021-02-01 21:31

1989 年,万维网诞生之后,HTTP 迅速成为主导世界的应用层协议。在今天,几乎任何场景都或多或少用到了 HTTP 协议。

在 30 多年的历史中,HTTP 协议本身有比较大的发展,同时,还有一些重大的变动也在酝酿之中。这些演化使得这个协议的表现力更强,性能更好,更能满足日新月异的应用需求。本文就来回顾和展望一下 HTTP 的历史和未来。

  • HTTP/0.9
  • HTTP/1.0
  • HTTP/1.1
  • HTTP/2
  • HTTP/3

HTTP/0.9

HTTP/0.9 诞生于 1991 年,是 HTTP 协议的最初版,构造十分简单:

  • 请求端只支持 GET 请求
  • 响应端只能返回 HTML 文本数据
GET /index.html


Hello World


请求示意图如下:

HTTP/0.9

可以看到,HTTP/0.9 只能发送 GET 请求,且每一个请求都单独创建一个 TCP 连接,响应端只能返回 HTML 格式的数据,响应完成之后 TCP 请求断开。

这样的请求方式虽然能够满足当时的使用需求,但也还是暴露出了一些问题。

HTTP/0.9 痛点:

  • 请求方式唯一,返回格式唯一
  • TCP 连接无法复用

HTTP/1.0

HTTP/1.0 诞生于 1996 年,它在 HTTP/0.9 的基础上,增加了 HTTP 头部字段,极大扩展了 HTTP 的使用场景。这个版本的 HTTP 不仅可以传输文字,还能传输图像、视频、二进制文件,为互联网的迅速发展奠定了坚实的基础。

核心特点如下:

  • 请求端增加 HTTP 协议版本,响应端增加状态码。
  • 请求方法增加 POST、HEAD。
  • 请求端和响应端增加头部字段。
    • Content-Type 让响应数据不只限于超文本。
    • Expires、Last-Modified 缓存头。
    • Authorization 身份认证。
    • Connection: keep-alive 支持长连接,但非标准。
GET /mypage.html HTTP/1.0
User-Agent: NCSA_Mosaic/2.0 (Windows 3.1)
200 OK
Date: Tue, 15 Nov 1994 08:12:31 GMT
Server: CERN/3.0 libwww/2.17
Content-Type: text/html



Hello World


请求示意图如下:

HTTP/1.0

可以看到,HTTP/1.0 扩展了请求方法和响应状态码,并且支持定义 HTTP 头部字段,通过 Content-Type 头,我们就能传输任何格式的数据了。同时可以看出,HTTP/1.0 仍然是一个请求对应一个 TCP 连接,不能形成复用。

HTTP/1.0 痛点:

  • TCP 连接无法复用。
  • HTTP 队头阻塞,一个 HTTP 请求响应结束之后,才能发起下一个 HTTP 请求。
  • 一台服务器只能提供一个 HTTP 服务。

HTTP/1.1

HTTP/1.1 诞生于 1999 年,它进一步完善了 HTTP 协议,一直用到了 20 多年后的今天,仍然是使用最广的 HTTP 版本。

核心特点如下:

  • 持久连接。

    • HTTP/1.1 默认开启持久连接,在 TCP 连接建立后不立即关闭,让多个 HTTP 请求得以复用。
  • 管线化技术。

    • HTTP/1.1 中,多个 HTTP 请求不用排队发送,可以批量发送,这就解决了 HTTP 队头阻塞问题。但批量发送的 HTTP 请求,必须按照发送的顺序返回响应,相当于问题解决了一半,仍然不是最佳体验。
  • 支持响应分块。

    • HTTP/1.1 实现了流式渲染,响应端可以不用一次返回所有数据,可以将数据拆分成多个模块,产生一块数据,就发送一块数据,这样客户端就可以同步对数据进行处理,减少响应延迟,降低白屏时间。
    • Bigpipe 的实现就是基于这个特性,具体是通过定义 Transfer-Encoding 头来实现的。
  • 增加 Host 头。

    • HTTP/1.1 实现了虚拟主机技术,将一台服务器分成若干个主机,这样就可以在一台服务器上部署多个网站了。
    • 通过配置 Host 的域名和端口号,即可支持多个 HTTP 服务:Host: :
  • 其他扩展。

    • 增加 Cache-Control、E-Tag 缓存头。
    • 增加 PUT、PATCH、HEAD、 OPTIONS、DELETE 请求方法。
GET /en-US/docs/Glossary/Simple_header HTTP/1.1
Host: developer.mozilla.org
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:50.0) Gecko/20100101 Firefox/50.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://developer.mozilla.org/en-US/docs/Glossary/Simple_header
200 OK
Connection: Keep-Alive
Content-Encoding: gzip
Content-Type: text/html; charset=utf-8
Date: Wed, 20 Jul 2016 10:55:30 GMT
Etag: "547fa7e369ef56031dd3bff2ace9fc0832eb251a"
Keep-Alive: timeout=5, max=1000
Last-Modified: Tue, 19 Jul 2016 00:59:33 GMT
Server: Apache
Transfer-Encoding: chunked
Vary: Cookie, Accept-Encoding



Hello World


请求示意图如下:

HTTP/1.1

可以看到,HTTP/1.1 可以并行发起多个请求,并且也能复用同一个 TCP 连接,传输效率得到了提升。但响应端只能按照发送的顺序进行返回,为此很多浏览器会为每个域名至多打开 6 个连接,用增加队列的方式减少 HTTP 队头阻塞。

HTTP/1.1 痛点:

  • HTTP 队头阻塞没有彻底解决,响应端必须按照 HTTP 的发送顺序进行返回,如果排序靠前的响应特别耗时,则会阻塞排序靠后的所有响应。

HTTP/2

HTTP/2 诞生于 2015 年,它的最大的特点是 All in 二进制,基于二进制的特性,对 HTTP 传输效率进行了深度优化。

HTTP/2 将一个 HTTP 请求划分为 3 个部分:

  • 帧:一段二进制数据,是 HTTP/2 传输的最小单位。
  • 消息:一个请求或响应对应的一个或多个帧。
  • 数据流:已建立的连接内的双向字节流,可以承载一条或多条消息。
HTTP/2 数据流、消息和帧

图中可以看到,一个 TCP 连接上有多个数据流,一个数据流承载着双向消息,一条消息包含了多个帧,每个帧都有唯一的标识,指向所在的数据流,来自不同数据流的帧可以交错发送,然后再根据每个帧头的数据流标识符重新组装,这样就实现了数据传输。

HTTP/2 核心特点如下:

  • 请求优先级
    • 多个 HTTP 请求同时发送时,会产生多个数据流,数据流中有一个优先级的标识,服务器端可以根据这个标识来决定响应的优先顺序。
  • 多路复用
    • TCP 传输时,不用按照 HTTP 的发送顺序进行响应,可以交错发送,接收端根据帧首部的标识符,就能找到对应的流,进而重新组合得到最终数据。
  • 服务器端推送
    • HTTP/2 允许服务器未经请求,主动向客户端发送资源,并缓存到客户端中,以避免二次请求。
    • HTTP/1.1 中请求一个页面时,浏览器会先发送一个 HTTP 请求,然后得到响应的 HTML 内容并开始解析,如果发现有