阅读了一篇HTTP相关的文章,内容写得很详细、全面,便对文章做了总结及翻译,以作记录。原文链接:cs.fyi/guide/http-…
总结
timeline
HTTP/0.9 - 1991 : 没有HTTP头
: GET请求方法
: 响应的内容是HTML
HTTP/1.0 - 1996 : 可处理更多的响应格式
: 增加POST、HEAD方法
: 请求和响应中添加HTTP头
: 添加了状态码
: 引入字符集
: 授权
: 缓存
: 内容编码
HTTP/1.1 - 1997 : PUT、PATCH等方法
: 引入持久连接
: 支持管道
: 分块传输
: 摘要认证和代理身份验证
: 引入缓存、字节范围等
HTTP/2 - 2015 : 二进制替代文本
: 多路复用
: 报头压缩
: 服务器推送
: 请求优先级
: 安全性
文章内容
什么是HTTP
HTTP是一个基于TCP/IP协议的应用层通信协议,它用于为客户端和服务器端的通信提供了标准。 它定义了内容如何被请求并传播到网络上。通过应用层协议,它可视为一个抽象层,它标准化 了主机之间(客户端和服务器端)如何进行通信。HTTP本身依赖TPC/IP来获取客户端和服务 器端的请求和响应。通常的,TCP使用80端口,HTTPS使用443端口(当然,也可以使用 其它的端口)。
HTTP/0.9 - 1991
HTTP的第一个文档版本是1991年提出的HTTP/0.9,它是有史以来最简单的协议,只有一个
GET方法。如果客户端需要访问服务器上的某些网页,它会发出如下的请求:
GET /index.html
然后收到服务器的如下响应:
(请求体)
关闭连接)
也就是说,服务器在接收到请求后,使用HTML进行应答,并且在内容被传输之后,关闭 连接。特点如下:
- 没有HTTP头
GET是唯一允许的请求方法- 响应的内容是HTML
HTTP/1.0 - 1996
不同于仅为HTML响应而设计的HTTP/0.9,HTTP/1.0可以处理其它响应格式,如图像、
视频文件、纯文本或任何其它的内容类型。它增加了更多的方法,POST和HEAD,
更改了请求/响应的格式,在请求和响应中都添加了HTTP头,添加了状态码来识别响应,
引入了字符集支持、多部分类型数据、授权、缓存、内容编码等。
一个HTTP/1.0请求和响应的样例如下:
GET / HTTP/1.0
Host: cs.fyi
User-Agent: Mozilla/5.0 (Machintosh; Intel Mac OS X 10_10_5)
Accept: */*
除了请求之外,客户端还发送了它的个人信息,所需的响应类型等信息。而在HTTP/0.9 中,客户端永远不能发送这样的信息,因为它没有HTTP头。
其对应的响应体样例如下:
HTTP/1.0 200 OK
Content-Type: text/plain
Content-Length: 137582
Expires: Thu, 05 Dec 1997 16:00:00 GMT
Last-Modified: Wed, 5 August 1996 15:55:28 GMT
Server: Apache 0.84
(响应体)
(连接关闭)
在这个版本中,请求和响应头仍然保持为ASCII编码,但响应体可以是任何类型的,即图像、
视频、HTML、纯文本或任何其它类型的内容。在HTTP引入这些内容之后,超文本一词
或许没有HMTP或者超媒体传输协议更加贴切。
HTTP/1.0的主要缺点之一是一个连接对应一个请求。也就是说,客户端从服务器获取内容时, 它都必须打开一个新的TCP连接,并且在该请求完成后,连接将 关闭。 对于下一个需求,它需要建立一个新的连接。这样子为什么不好呢?让我们假设 你访问的网页有10张图片,5个样式表和5个javascript文件,总共有20个项目需要在对 该网页进行请求时获取。由于服务器在请求完成后立即关闭连接,因此将有20个单独 的连接,其中每个项目将在其单独的连接上逐一提供服务。这种大量的连接会导致严重的性能下降, 因为建立新的TCP连接需要进行三次握手,然后还要进行慢启动,这会带来严重的性能开销。
三次握手
三次握手可简要概括为下图:
在HTTP/1.0的一些实现中,人们试图通过引入一个名为Connection: keep-alive的新标签
来解决这个问题,它的意思是告诉服务器”嘿,服务器,不要关闭这个连接,我还需要它”。但是
,它仍然没有得到广泛的支持,问题仍然存在。
除了无连接之外,HTTP也是一个无状态协议,即服务器不维护客户端的信息,所以每个请求都必 须有服务器自己完成请求所需的信息,而不与任何旧请求相关联。这使问题更严重了,客户端除了打 开的大量连接之外,它还会在网络上发送一些冗余的数据,从而增加带宽负担。
HTTP/1.1 - 1997
这个版本对之前做了很多改进,如下:
- 增加了新的HTTP方法,包括
PUT、PATCH、OPTIONS和DELETE - 需要提供主机名标识中的主机头
- 引入了持久连接,即连接在默认情况下不会关闭,而是保持打开状态,从而允许多个顺序请求。
要关闭连接,请求头
Connection: close必须是可用的。客户端通常在最后一个请求中发送此头以安全关闭连接。 - 它还引入了对管道的支持,在同一个连接上,客户端可以向服务器发送多个请求,而无需等待
服务器的响应,并且服务器必须按照接收请求的顺序发送响应。但是你可能会问,客户端怎么知
道这是第一个响应下载完成和下一个响应内容开始的点呢?好吧,为了解决这个问题,必
须存在
Content-Length头,客户端可以使用它来标识响应的结束位置,并开始等待下一个响应。 - 分块传输。对于动态内容,当服务器在开始传输时无法真正知道内容长度时,可以开始分块发
送内容,并在发送时为每个分块添加内容长度。当所有的块被发送时,即整个传输已经完成,
它会发送一个空块,即
Content-Length设置为0的块,以便识别传输已经完成的客户端。为了 通知客户端有分块传输,服务器包含了首部Transfer-Encoding: chunked - 提供了摘要认证和代理身份验证
- 缓存、字节范围、字符集、语言协商、客户端cookies、增强的压缩支持、新的状态码等
更详细的HTTP/1.0和HTTP/1.1的内容可查阅:www.ra.ethz.ch/cdstore/www…
HTTP/1.1于1999年推出,多年来一直是一项标准。尽管它比其前身有了很大的改进,但随着网 络的日新月异,它开始显示出其局限性。如今加载网页所需的资源比以往任何时候都要多。一个 简单的网页现在需要打开30多个连接。那么,为什么HTTP/1.1需要这么多连接呢?原因在于 ,HTTP/1.1在任何时刻只能有一个活跃的连接。HTTP/1.1通过引入管道化试图解决这个问题 ,但它并没有完全解决问题,因为头部阻塞会导致慢速或繁重的请求阻塞其后的请求,一旦请求 被困在管道中,它将不得不等待下一个请求完成。为了克服HTTP/1.1的这些局限性,开发人员 开始实施各种方案解决,例如使用spritesheets、CSS中的编码图像、单个庞大的CSS/Java Script文件、域名分片等。
SPDY - 2009
谷歌开始尝试采用其他协议来加快网络速度,提供网络安全性,并减少网页加载时间。在2009年, 他们宣布了SPDY协议。
如果我们不断增加带宽,网络性能在开始时会有所提高,但到了一个点,性能就没有多少提高了。 但是如果不断降低延迟,会有一个恒定的性能增益。这是SPDY背后性能提升的核心思想:减少 延迟以提高网络性能。(延迟是数据在源和目的地之间传输所需的时间,带宽是每秒传输的数据量。
SPDY的特性包括多路复用、压缩、优先级、安全性等,它是存在于HTTP应用层上的转换层,在 将请求发送到网络之前对其进行修改。2015年,谷歌不想有两个相互竞争的标准,所以决定将 SPDY合并到HTTP中,诞生了HTTP/2,并弃用了SPDY。
HTTP/2 - 2015
HTTP/2是为低延迟的内容传输而设计的,它与HTTP/1.1的主要特性或区别如下:
- 二进制替代文本
- 多路复用——在单个连接上允许多个异步的HTTP请求
- 使用HPACK压缩报头
- 服务器推送——对单个请求进行多个响应
- 请求优先级
- 安全性
1 二进制协议
HTTP/2倾向于通过将HTTP/1.x变成二进制协议来解决存在于HTTP/1.x中的延迟增加问题。 作为二进制协议,它更容易解析,但与HTTP/1.x不同的是,它不再人眼可读。HTTP/2的 主要组成部分是帧和流。
帧和流
HTTP消息由一个或多个帧组成:有一个HEADERS帧用于元数据,DATA帧用于有效负载,
以及其他类型的帧。
每个HTTP/2的请求和响应都有一个唯一的流ID,并被划分为帧。帧是二进制数据块。帧的集合 称为流。每个帧都有一个流id来标识它所属的流,每个帧都有一个公共的首部。此外,除了流 ID是唯一的,客户端发起的任何请求都使用奇数,服务器响应的流ID是偶数。
除了报头和数据,另一个帧类型是RST_STREAM,它是一种特殊的帧类型,用于中止一些流
,即客户端可以发送此帧来让服务器知道我不再需要此流。在HTTP/1.1中,让服务器停止向
客户端发送响应的唯一方法是关闭连接,这会导致延迟增加,因为必须为任何连续的请求打开
一个新连接。而在HTTP/2中,客户端可以使用RST_STREAM,并在连接仍然打开且其他流仍
在使用时停止接收特定的流。
2 多路复用
由于HTTP/2现在是二进制协议,它使用帧和流进行请求和响应,一旦TCP连接打开,所有 流都会通过同一个连接异步发送,而不会打开任何额外的连接。反过来,服务器以相同的异 步方式响应,即响应没有顺序,客户端使用分配的流id来识别特定分组所属的流。这也解决 了HTTP/1中存在的队首阻塞问题。例如,客户端不必等待正在花费时间的请求,而其他请 求仍将被处理。
3 首部压缩
它是一个单独的RFC的一部分,该RFC专门用于优化发送的headers。它的本质是,当我们 不断地从同一个客户端访问服务器时,我们会不断地发送大量冗余数据报头,有时可能会有 cookie增加报头大小,从而导致带宽占用和延迟增加。为了解决这个问题,HTTP/2引入 了首部压缩。
与请求和响应不同的是,报头不压缩为gzip或compress等格式,但报头压缩有一种不同 的机制,即文字值使用Huffman编码,并由客户端和服务器维护报头表,客户端和服务器 在后续请求中省略任何重复的报头(例如用户代理等),并使用双方维护的报头表引用它们。
4 服务器推送
服务器推送是HTTP/2的另一个重要特性,服务器知道客户端将请求某个资源,就可以在客户 端没有请求的情况下将资源推送给客户端。例如,假设浏览器加载一个web页面,它解析整个 页面以找出它必须从服务器加载的远程内容,然后向服务器发送相应的请求以获取该内容。
允许服务器推送它知道的客户端需要的数据,从而减少往返次数。具体做法是,服务器发
送一个名为PUSH_PROMISE的特殊帧通知客户端:“嘿,我要把这个资源发给你!不
要向我要。”PUSH_PROMISE帧与导致推送发生的流相关联,它包含被承诺的流ID,即
服务器将在该流上发送要推送的资源。
5 请求优先级
客户端可以在打开流的HEADERS帧中包含优先级信息,从而为流指定优先级。在其他
任何时候,客户端可以发送一个优先级帧来改变流的优先级。
在没有任何优先级信息的情况下,服务器异步处理请求,即没有任何顺序。如果给 流分配了优先级,那么服务器会根据这个优先级信息决定处理哪个请求需要多少资源。
6 安全
关于HTTP/2是否应该强制要求安全性(通过TLS),有过广泛的讨论。最后,决定不强制 执行。然而,大多数供应商表示,他们只支持通过TLS使用的HTTP/2。所以,虽然HTTP/2 在规范上不需要加密,但它在默认情况下是强制性的。除此之外,通过TLS实现的HTTP/2也有 一些要求。必须使用TLS 1.2或更高版本,必须有一定的最小密钥长度,需要临时密钥等。