HTTP的演变

本博客 hjy-xh,转载请申明出处

HTTP 概述

超文本传输协议(HyperText Transfer Protocol)是一种用于分布式、协作式和超媒体信息系统的应用层协议,它为 Web 浏览器与 Web 服务器之间的通信而设计,是万维网的数据通信的基础

HTTP 具备几个特征:

  • 遵循经典的客户端—服务端模型,客户端打开一个连接以发出请求,然后等待直到收到服务器端响应
  • 无状态,这意味着服务器不会在两个请求之间保留任何数据(状态)

演变过程

万维网的发明

1989 年,当时在 CERN 工作的 Tim Berners-Lee 博士写了一份关于建立一个通过网络传输超文本系统的报告。这个系统起初被命名为 Mesh,在随后的 1990 年项目实施期间被更名为万维网(World Wide Web)。它在现有的 TCP 和 IP 协议基础之上建立,由四个部分组成:

  • 一个用来表示超文本文档的文本格式,超文本标记语言(HTML)。
  • 一个用来交换超文本文档的简单协议,超文本传输协议(HTTP)。
  • 一个显示(以及编辑)超文本文档的客户端,即网络浏览器。第一个网络浏览器被称为 WorldWideWeb。
  • 一个服务器用于提供可访问的文档,即 httpd 的前身。
    这四个部分完成于 1990 年底,且第一批服务器已经在 1991 年初在 CERN 以外的地方运行了。1991 年 8 月 16 日,Tim Berners-Lee 在公开的超文本新闻组上发表的文章被视为是万维网公共项目的开始。

HTTP 在应用的早期阶段非常简单,后来被称为 HTTP/0.9,有时也叫做单行(one-line)协议。

HTTP/0.9——单行协议

最初版本的 HTTP 协议并没有版本号,后来它的版本号被定位为0.9,以区分后来的版本

HTTP/0.9 极其简单,请求由单行指令构成,以唯一可用的GET方法开头,其后跟资源的路径

1
GET /mypage.html

而响应也非常简单:只有响应文档本身:

1
2
3
<html>
这是一个非常简单的 HTML 页面
</html>

HTTP/0.9 的响应内容不包含 HTTP 头,这意味着只有 HTML 文件可以传送,无法传输其它类型的文件,也没有状态码和错误代码

HTTP/1.0——构建可拓展性

在 1991-1995 年,这些新扩展并没有被引入到标准中以促进协助工作,而仅仅作为一种尝试。服务器和浏览器添加这些新扩展功能,但出现了大量的互操作问题。直到 1996 年 11 月,一份新文档(RFC 1945)被发表出来,文档 RFC 1945 定义了 HTTP/1.0,但它是狭义的,并不是官方标准。新增了一下主要内容:

  • 协议版本信息现在会随着每个请求发送(HTTP/1.0 被追加到了 GET 行)
  • 状态码会在响应开始时发送,使浏览器能了解请求执行成功或失败,,并相应调整行为(如更新或使用本地缓存)
  • 引入了 HTTP 头的概念,无论是对于请求还是响应,允许传输元数据,使协议变得非常灵活,更具扩展性
  • 具备了传输除纯文本 HTML 文件以外其他类型文档的能力
  • 除了 GET 命令,还引入了 POST 命令和 HEAD 命令,丰富了浏览器与服务器的互动手段

请求格式如下:

1
2
3
4
5
6
7
8
9
10
11
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
<HTML>
一个包含图片的页面
<IMG SRC="/myimage.gif">
</HTML>

一些常见的头信息字段

  • Content-Type
    服务器回应客户端时,需要告知其数据格式(MIME type):

    • text/html
    • text/css
    • image/png
    • image/gif
    • application/javascript
    • application/octet-stream
  • Content-Encoding
    由于传输的数据可能比较大,可以将数据进行压缩:

    • content-encoding: gzip

    • Content-Encoding: compress

    • Content-Encoding: deflate

      而客户在请求时,可以通过Accept-Encoding字段说明自己可以接受哪些压缩方法:Accept-Encoding: gzip, deflate

HTTP/1.1——标准化的协议

HTTP/1.0 多种不同的实现方式在实际运用中显得有些混乱。自 1995 年开始,即 HTTP/1.0 文档发布的下一年,就开始修订 HTTP 的第一个标准化版本。在 1997 年初,HTTP1.1 标准发布

HTTP/1.1 消除了大量歧义内容并引入了多项改进:

  • 连接可以复用,节省了多次打开 TCP 连接加载网页文档资源的时间(Connection: keep-alive)
  • 增加管线化技术,允许在第一个应答被完全发送之前就发送第二个请求,以降低通信延迟
    • 举例来说,客户端需要请求两个资源。以前的做法是,在同一个 TCP 连接里面,先发送 A 请求,然后等待服务器做出回应,收到后再发出 B 请求。管道机制则是允许浏览器同时发出 A 请求和 B 请求,但是服务器还是按照顺序,先回应 A 请求,完成后再回应 B 请求
    • 一个 TCP 连接现在可以传送多个回应,势必就要有一种机制,区分数据包是属于哪一个回应的。这就是 Content-length 字段的作用,声明本次回应的数据长度:Contene-Length: 3000,在 1.0 版中,Content-Length 字段不是必需的,因为浏览器发现服务器关闭了 TCP 连接,就表明收到的数据包已经全了
  • 支持响应分块(Transfer-Encoding: chunked)
  • 引入额外的缓存控制机制
  • 引入内容协商机制,包括语言、编码、类型等,并允许客户端和服务器之间约定以最合适的内容进行交换
  • 凭借Host标头,能够使不同域名配置在一个 IP 地址的服务器上(虚拟主机的兴起)

一个典型的请求流程,所有请求都通过一个连接实现,看起来就像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
GET /zh-CN/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/zh-CN/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

(content)


GET /static/img/header-background.png 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: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: https://developer.mozilla.org/zh-CN/docs/Glossary/Simple_header

200 OK
Age: 9578461
Cache-Control: public, max-age=315360000
Connection: keep-alive
Content-Length: 3077
Content-Type: image/png
Date: Thu, 31 Mar 2016 13:34:46 GMT
Last-Modified: Wed, 21 Oct 2015 18:27:50 GMT
Server: Apache

(image content of 3077 bytes)

HTTP/1.1 在 1997 年 1 月以 RFC 2068 文件发布

超过15年的拓展

由于 HTTP 协议的可扩展性使得创建新的头部和方法是很容易的。即使 HTTP/1.1 协议进行过两次修订,RFC 2616 发布于 1999 年 6 月,而另外两个文档 RFC 7230-RFC 7235 发布于 2014 年 6 月(在 HTTP/2 发布之前)。HTTP/1.1 协议已经稳定使用超过 15 年了

HTTP 用于安全传输

通过加密来保证服务器和客户端之间交换消息的真实性

额外的加密传输层:SSL

SSL 在标准化道路上最终成为了 TLS

HTTP 用于复杂应用

在 2000 年,一种新的使用 HTTP 的模式被设计出来:具象状态传输(representational state transfer) (或者说 REST),RESTful API 在 2010 年变得非常流行

自 2005 年以来,可用于 Web 页面的 API 大大增加,其中几个 API 为特定目的扩展了 HTTP 协议,大部分是新的特定 HTTP 头:

  • Server-sent events,服务器可以偶尔推送消息到浏览器
  • WebSocket,一个新协议,可以通过升级现有 HTTP 协议来建立

放松安全措施——基于当前的 Web 模型

HTTP 和 Web 安全模型——同源策略是互不相关的。事实上,当前的 Web 安全模型是在 HTTP 被创造出来后才被发展的!这些年来,已经证实了它如果能通过在特定的约束下移除一些这个策略的限制来管的宽松些的话,将会更有用。这些策略导致大量的成本和时间被花费在通过转交到服务端来添加一些新的 HTTP 头来发送。这些被定义在了跨源资源共享(CORS)和内容安全策略(CSP)规范里。

不只是这大量的扩展,很多的其他的头也被加了进来,有些只是实验性的。比较著名的有 DNT(Do Not Track)来控制隐私,X-Frame-Options,还有很多

HTTP/2——为了更优异的表现

这些年来,网页愈渐变得的复杂,甚至演变成了独有的应用,可见媒体的播放量,增进交互的脚本大小也增加了许多:更多的数据通过 HTTP 请求被传输。HTTP/1.1 链接需要请求以正确的顺序发送,理论上可以用一些并行的链接(尤其是 5 到 8 个),带来的成本和复杂性堪忧。比如,HTTP 管线化(pipelining)就成为了 Web 开发的负担。为此,在 2010 年早期,谷歌通过实践了一个实验性的 SPDY 协议。这种在客户端和服务器端交换数据的替代方案引起了在浏览器和服务器上工作的开发人员的兴趣。明确了响应数量的增加和解决复杂的数据传输,SPDY 成为了 HTTP/2 协议的基础。

HTTP/2 在 HTTP/1.1 有几处基本的不同:

  • HTTP/2 采用二进制格式而非文本格式
  • 这是一个多路复用协议。并行的请求能在同一个链接中处理,移除了 HTTP/1.x 中顺序和阻塞的约束。
  • 压缩了标头。因为标头在一系列请求中常常是相似的,其移除了重复和传输重复数据的成本。
  • 让服务器可以将响应主动“推送”到客户端缓存中

后 HTTP/2 进化

随着 HTTP/2.的发布,就像先前的 HTTP/1.x 一样,HTTP 没有停止进化,HTTP 的扩展性依然被用来添加新的功能。特别的,我们能列举出 2016 年里 HTTP 的新扩展:

  • 对 Alt-Svc 的支持允许了给定资源的位置和资源鉴定,允许了更智能的 CDN 缓冲机制。
  • 客户端提示(client hint) 的引入允许浏览器或者客户端来主动交流它的需求,或者是硬件约束的信息给服务端。
  • 在 Cookie 头中引入安全相关的的前缀,现在帮助保证一个安全的 Cookie 没被更改过。

HTTP/2 不足之处

  • 建立连接时间长(本质上是TCP的问题)
  • 队头阻塞问题

HTTP/3——基于 QUIC 的 HTTP

HTTP 的下一个主要版本,HTTP/3 有这与 HTTP 早期版本的相同语义,但在传输层部分使用 QUIC (en-US) 而不是 TCP。到 2022 年 10 月,26% 的网站正在使用 HTTP/3。

QUIC 旨在为 HTTP 连接设计更低的延迟。类似于 HTTP/2,它是一个多路复用协议,但是 HTTP/2 通过单个 TCP 连接运行,所以在 TCP 层处理的数据包丢失检测和重传可以阻止所有流。QUIC 通过 UDP 运行多个流,并为每个流独立实现数据包丢失检测和重传,因此如果发生错误,只有该数据包中包含数据的流才会被阻止。

RFC 9114 定义的 HTTP/3 被大多数主流浏览器所支持,包括 Chromium(及其他的变体,例如 Chrome 和 Edge)和 Firefox。

参考

MDN

HTTP 协议入门

HTTP 的发展