HTTP 协议规定了客户端和服务器直接通信的规范,在网络模型中属于应用层,与开发者直接打交道,它本身也是基于 TCP 和 IP 协议来获取请求和响应,默认 HTTP 使用 TCP 的 80 端口,HTTPS 使用 443 端口。

HTTP 协议发展至今,已经经历过好几个版本。

1. HTTP/0.9

HTTP 1991 年发布的版本称为 HTTP/0.9,是一个很简单的协议,只有一个 GET 方法,不支持多媒体内容的 MIME 类型、各种 HTTP 首部,或者版本号。该协议定义的初衷是为了获取简单的 HTML 对象。

1
GET /index.html

服务端返回的响应内容格式

1
2
(response body)
(connection closed)

它很快就被 HTTP/1.0 取代了。

2. HTTP/1.0

1996,HTTP1.0 大大改进了之前的协议版本,并得到广泛使用。

HTTP/0.9 只有 GET 方法,并且响应只能是 HTML,而 1.0 增加了更多的方法,比如 POST、HEAD;响应内容可以是图片视频文本或者其它类型。

1.0 的请求和响应都增加了版本号,头部信息,响应内容有状态码,引入字符集,授权认证,缓存,内容编码等。

1
2
3
4
GET / HTTP/1.0
Host:baidu.cn
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2)
Accept:*/*
1
2
3
4
5
6
7
8
HTTP/1.0 200 OK
Content-Type:text/plain
Content-Length:123582
Expires:Wed, 17 Jan 2018 14:37:52 GMT
Server:tengine

(response body)
(connection closed)

HTTP 1.0 一个主要的缺点就是,一个连接只能有一个请求,即每次请求都会重新建立一个 TCP 连接,TCP 建立连接需要三次握手,加上慢启动的特性,这将是很耗资源和性能的一个步骤,于是有些 HTTP 1.0 的实现版本,在请求头中添加了一个 Connection:keep-alive的标记,但是并没有被广泛支持。

因为 HTTP 1.0 的无连接,使得它也是一种无状态的协议。服务端没法维护客户端的信息,致使每个请求都得额外的去携带一些必要的信息,在连接很多的情况下,造成很多带宽的压力。

3. HTTP/1.1

1999 年,HTTP 1.1 发布了,相比 1.0,同样改进很大,也是现在用的最为广泛的一个版本。

3.1 持久连接

1
2
Connection: Keep-Alive 
Keep-Alive: max=5, timeout=120

HTTP 1.1 建立连接后,默认不会被断开,它允许多个有序的请求,客户端如果想要关闭连接,可以在最后一个请求的请求头中,加上 Connection:close来安全关闭这个连接。或者连接闲置达到指定时间,也可以自动断开连接。

3.2 管道机制

HTTP 1.1 引入了管道机制,即在一个连接上,客户端请求时不需要等待服务器响应后,才去发送下一个请求,客户端可以连续发送几个请求,服务端按照接受请求的顺序,依次把响应返回回来。

这里有一个问题,即客户端如何区分哪里是第一个响应的内容,哪里是下一个响应的内容呢?HTTP 1.1 为此添加了 Content-Length首部,用它来标记响应内容的结束位置,以及下一个响应内容的开始位置。

1
Content-Length:1234

3.3 分块传输

使用 Content-Length 字段,前提是服务端必需要知道返回数据的长度,对于一些耗时的数据操作,服务端如果等所有操作都做完,才返回数据,效率非常不高,为此,采用了一种分块传输的处理方法,即产生一块数据,就发送一块。

具体的形式是,在响应头部返回 Transfer-Encoding 字段,表明数据是有未定的数据块组成。

1
Transfer-Encoding:chunked

每一个分块,都添加一个 Content-Length,当所有的数据块都传输完成时,范湖一个空的 chunked,Content-Length 设为 0,来表示传输完成。

3.4 其它功能

  • 新增 HTTP 方法,包括 PUT,PATCH,OPTIONS,DELETE。
  • HTTP 1.0 的 Header 中,Host 字段不是必需的,而 HTTP 1.1 必需。
  • 客户端 cookies
  • 摘要和代理认证

3.5 缺点

HTTP 1. 1 虽然可以持久连接,并引入了管道机制,但核心还是得按照顺序处理请求,返回响应内容。只有处理完一个回应,才会处理下一个回应,所以,如果第一个回应处理特别慢,那么后面的只能等待,这就是「对头堵塞」(Head-of-line blocking)。

开发者对这个问题,也提供了一些解决思路:

  • 减少请求:网页的样式和脚本合并,图片嵌入 css 中
  • 多开持久连接:域名分片

4. SPDY

2009年,谷歌宣布了自行研发的 SPDY 协议,主要解决传输速度和网络安全的问题。通过减少 HTTP 1.1 响应阻塞延时,来提高传输速度和性能。

SPDY 协议的特性包括复用,压缩,优先级,安全等。2015 年,Google 决定将 SPDY 合并到 HTTP 标准中,并命名为 HTTP / 2。

5. HTTP/2

HTTP/2 的特性是低延时传输,相比 HTTP 1. 1,主要在二进制协议,多路复用,头信息压缩,推送,请求优先级,安全等方面做了处理。

5.1 二进制协议

HTTP/2 将数据分成一个一个的帧,头帧存储元数据,数据帧存放数据,以及一些其他的帧。HTTP 1.1 的头信息是文本(ASCII 编码),数据体可以是文本,也可以是二进制,而 HTTP/2 是一个彻底的二进制协议。

每个请求和响应,都有一个唯一的数据流 id,并且流数据都被划分为帧(二进制数据),每个帧都有这个唯一的流 id ,请求的流 id 为奇数,响应的流 id 为偶数。

5.2 多路复用

基于二进制协议,TCP 连接打开的时候,所有的数据流都可以传输,而不必打开额外的连接,并且因为有流 id 作为标记,多个响应数据不必要等待就可以直接传回来,解决了 HTTP 1.1 队头阻塞的问题。

5.3 头部压缩

当我们不断地从同一个客户端访问服务器时,有很多重复的数据比如 cookie 数据,会在请求头上反复发送,增加带宽的使用以及延迟。为了解决这个问题,HTTP/2 引入了头压缩。

头信息不是以 gzip 或 compress 等格式进行压缩,而是使用霍夫曼编码对文本值进行编码,所有头信息都会放在一张表里面,由客户端和服务器共同维护,随后的请求中省略任何重复的标题,使用一个索引号,服务端根据索引号从维护的表中引用它们。

5.4 推送

服务器推送是HTTP / 2的另一个巨大功能,服务器知道客户端将要请求某个资源,可以将客户端推送到客户端,甚至不需要客户端询问它。

比如一个网页请求,里面有图片资源,脚本资源,现在服务端返回资源时,发现网页请求里面还有其他资源请求,就主动把其他请求的响应也返回回去了,减少了很多请求。

5.5 请求优先级

客户端可以在请求头里添加一个优先级的信息来为流分配优先级。

如果流没有任何优先级信息,服务器则异步处理请求,即没有任何顺序。如果流有优先级,那么根据这个优先级信息,服务器决定需要给多少资源来处理哪个请求。

5.6 安全

对于 HTTP/2 的安全性(通过TLS)是否强制进行了广泛的讨论。最后,决定不强制执行。但是,大多数供应商表示,只有在通过 TLS 使用 HTTP/2 时才会支持。所以,尽管 HTTP/2 不需要按规格加密,但是它默认情况下已经成为强制,通过 TLS 实现的 HTTP/2 必须使用 TLS 1.2 版或更高版本,必须具有一定的最小密钥级别,需要临时密钥等。

参考

HTTP 协议入门

Journey to HTTP/2