HTTP发展史
# HTTP/0.9
HTTP/0.9是最早的版本,这个版本非常简单,只有一个命令 GET
GET /mypage.html
响应也极其简单,只包含文档本身
<html>
这是一个非常简单的 HTML 页面
</html>
2
3
没有HEADER等描述数据的信息,服务器发送完毕,就关闭TCP连接
# HTTP/1.0
相对于HTTP/0.9,引入了更多的功能和特性。主要有以下几点
- 除了GET命令,还增加了POST命令和HEAD命令
- 引入了HTTP header(头信息),无论请求还是响应,允许传输元数据,使协议更灵活
- 凭借 Content-Type 标头,具备了传输除纯文本 HTML 文件以外其他类型文档的能力,比如图像视频等
- 新增了状态码status code、多字符集支持、多部分发送(multi-part type)、权限(authorization)、缓存(cache)、内容编码(content encoding)等
一个典型的请求像这样:
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>
2
3
4
5
6
7
8
9
10
11
接下来是第二个连接,获取图片信息
GET /myimage.gif HTTP/1.0
User-Agent: NCSA_Mosaic/2.0 (Windows 3.1)
200 OK
Date: Tue, 15 Nov 1994 08:12:32 GMT
Server: CERN/3.0 libwww/2.17
Content-Type: text/gif
(这里是图片内容)
2
3
4
5
6
7
8
相较于HTTP/0.9,1.0版本内容大大增加,但仍然有很多缺点,最主要的缺点是每个TCP连接只能发送一个请求。 TCP建立连接需要三次握手,这导致HTTP/1.0的性能比较差,随着网页展示内容的丰富性持续发展,这个问题就越来越明显了。
# HTTP/1.1
就在HTTP/1.0发布的几个月后,发布了HTTP协议的第一个标准化版本HTTP1.1。HTTP1.1消除了大量歧义内容并新增了很多改进:
- 持久连接:TCP连接默认不关闭,节省了多次打开TCP连接的时间。
- 管道机制Pipeline:允许在第一个应答被完全发送之前就发送第二个请求,以降低通信延迟。
- 支持响应分块:产生一块数据则发送一块,即流模式(stream),在请求或回应的头信息中有Transfer-Encoding字段,表明回应由数据块组成
- 新增Host字段,能够使不同域名配置在同一个 IP 地址的服务器上。
- 引入了若干缓存机制
# HTTP缓存机制
HTTP缓存有强缓存和协商缓存。强缓存和协商缓存在缓存命中时都会直接使用本地的缓存副本,区别在于协商缓存会向服务器发送一次请求来确认是否使用缓存。
当浏览器未命中强缓存时,则会命中协商缓存
# 强缓存
缓存策略:如果缓存资源有效,则直接使用缓存资源,不再向服务器重新请求 设置方式:HTTP标头字段
1.Expires:指定资源的过期时间,是一个绝对时间。当本地时间小于设置的时间,则使用缓存。 注意:无效的日期,比如 0,代表着过去的日期,即该资源已经过期。如果在Cache-Control响应头设置了 "max-age" 或者 "s-max-age" 指令,那么 Expires 头会被忽略。
2.cache-control:设置缓存机制,常用字段有
[1]no-cache:在发布缓存副本之前,强制进行协商缓存验证
[2]no-store: 不使用任何缓存
[3]max-age:相对过期时间,多少秒内有效
# 协商缓存
缓存策略:在使用缓存时会向服务器发送请求,问询资源是否发生更改,若未发生更改则返回304状态,客户端直接使用缓存,如果资源发生改变,则使用服务器返回资源 设置方式:HTTP标头字段
1.Last-Modified:表示文件最后被修改的日期,客户端再次请求时,会通过If-Modified-Since字段将Last-Modified值发送给服务器,询问服务器在这个日期后是否有更新。
2.Etag:服务端通过某种算法计算出该资源的唯一标识符。If-None-Match会将Etag发送给服务器,询问该资源是否有变动,有变动的话将新的资源返回。Etag优先级比Last-Modified高。
# HTTP/2.0
2015年5月正式发布HTTP/2协议规范,该协议使用多路复用机制,实现一个域名只使用一个TCP长连接,并消除了队头阻塞问题。多路复用技术能充分利用带宽,最大限度规避了TCP慢启动所带来的问题,使得页面资源的传输速度得到了大幅提升。 使用HTTP/2能带来20% ~ 60%的效率提升。 HTTP/2添加了一个二进制分帧层,将经过的请求转换为一个个带有请求ID编号的帧,服务器接收到所有帧之后,将所有相同ID的帧合并为一条完整的请求信息,处理完请求后,将响应也同样用二进制分帧层转换为一个个带有请求ID编号的帧,浏览器接收到响应帧后根据ID编号将数据提交给对应的请求。
HTTP/2 是二进制协议而不是文本协议。 这是一个多路复用协议。并行的请求能在同一个链接中处理,移除了 HTTP/1.x 中顺序和阻塞的约束 压缩了标头
- 二进制分帧:HTTP/2 的所有帧都采用二进制编码
- 多路复用 (Multiplexing)
- 请求优先级
- header 压缩
- 服务端推送
二进制分帧:HTTP/2 的所有帧都采用二进制编码 先理解几个概念:
帧:客户端与服务器通过交换帧来通信,帧是基于这个新协议通信的最小单位。
消息:是指逻辑上的 HTTP 消息,比如请求、响应等,由一或多个帧组成。
流:流是连接中的一个虚拟信道,可以承载双向的消息;每个流都有一个唯一的整数标识符(1、2…N);
HTTP/2 采用二进制格式传输数据,而非 HTTP 1.x 的文本格式,二进制协议解析起来更高效。 HTTP / 1 的请求和响应报文,都是由起始行,首部和实体正文(可选)组成,各部分之间以文本换行符分隔。HTTP/2 将请求和响应数据分割为更小的帧,并且它们采用二进制编码。
# 帧、流、消息的关系
每个数据流都以消息的形式发送,而消息又由一个或多个帧组成。 帧是流中的数据单位。一个数据报的 header 帧可以分成多个 header 帧,data 帧可以分成多个 data 帧。
# 多路复用 (Multiplexing)
多路复用允许同时通过单一的 HTTP/2 连接发起多重的请求-响应消息。即连接共享,即每一个 request 都是是用作连接共享机制的。一个 request 对应一个 id,这样一个连接上可以有多个 request,每个连接的 request 可以随机的混杂在一起,接收方可以根据 request 的 id 将 request 再归属到各自不同的服务端请求里面。
# 请求优先级
- 把 HTTP 消息分解为很多独立的帧之后,就可以通过优化这些帧的交错和传输顺序,每个流都可以带有一个 31 比特的优先值:0 表示最高优先级;2 的 31 次方-1 表示最低优先级。
- 服务器可以根据流的优先级,控制资源分配(CPU、内存、带宽),而在响应数据准备好之后,优先将最高优先级的帧发送给客户端。
- HTTP 2.0 一举解决了所有这些低效的问题:浏览器可以在发现资源时立即分派请求,指定每个流的优先级,让服务器决定最优的响应次序。这样请求就不必排队了,既节省了时间,也最大限度地利用了每个连接。
# header 压缩
HTTP1.x 的 header 带有大量信息,而且每次都要重复发送,HTTP/2 使用 encoder 来减少需要传输的 header 大小,通讯双方各自cache 一份 header fields 表,既避免了重复 header 的传输,又减小了需要传输的大小。 为了减少这块的资源消耗并提升性能, HTTP/2 对这些首部采取了压缩策略:
- HTTP/2 在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键-值对,不再重复发送 header
- 首部表在 HTTP/2 的连接存续期内始终存在,由客户端和服务器共同渐进地更新;
- 每个新的首部键-值对要么被追加到当前表的末尾,要么替换表中之前的值
# 服务端推送
Server Push 即服务端能通过 push 的方式将客户端需要的内容预先推送过去,也叫“cache push”。 服务器可以对一个客户端请求发送多个响应。服务器向客户端推送资源无需客户端明确地请求,服务端可以提前给客户端推送必要的资源,这样可以减少请求延迟时间,例如服务端可以主动把 JS 和 CSS 文件推送给客户端,而不是等到 HTML 解析到资源时发送请求
# HTTP/3.0
弃用TCP协议,改为使用基于UDP协议的QUIC协议实现。 解决了队头阻塞的问题