特性 | HTTP1.0 | HTTP1.1 | HTTP2.0 |
---|---|---|---|
持续连接 | ✗ | ✔ | ✔ |
断点续传 | ✗ | ✔ | ✔ |
Host 头 | ✗ | ✔ | ✔ |
请求方法 | GET 、HEAD 、POST | 以上+ OPTIONS 、PUT 、DELETE 、TRACE 、CONNECT | 以上全部 |
缓存控制 | Expire 、Last-Modefied 、Pragma | 以上+ ETag 、Cache-Control | 以上全部 |
二进制分帧 | ✗ | ✗ | ✔ |
header压缩 | ✗ | ✗ | ✔ |
多路复用 | ✗ | ✗ | ✔ |
服务器推送 | ✗ | ✗ | ✔ |
队头阻塞 | ✔ | ✔ | ✗ |
持续连接
HTTP1.0
每发送一次请求,都得建立一次TCP连接。
HTTP1.1
使用了持续连接,能够让服务器在发送响应后仍然在一段时间内保持这条连接,使同一个客户和该服务器可以继续在这条连接上传送后续的HTTP请求报文和响应报文。
HTTP1.1
的持续连接有两种工作方式,即非流水线方式和流水线方式。
非流水线方式的特点,是客户在收到前一个响应后才能发出下一个请求。因此,在TCP连接已建立后,客户每访问一次对象都要用去一个往返时间RTT。这比非持续连接要用去两倍RTT的开销,节省了建立TCP连接所需的一个RTT时间。但非流水线方式还是有缺点的,因为服务器在发送完一个对象后,其TCP连接就处于空闲状态,浪费了服务器资源。
流水线方式的特点,是客户在收到HTTP的响应报文之前就能够接着发送新的请求报文。于是一个接一个的请求报文到达服务器后,服务器就可连续发回响应报文。因此,使用流水线方式时,客户访问所有的对象只需花费一个RTT时间。流水线工作方式使TCP连接中的空闲时间减少,提高了下载文档效率。
HTTP 1.1支持长连接(PersistentConnection)和请求的流水线(Pipelining)处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP1.1中默认开启Connection: keep-alive,一定程度上弥补了HTTP1.0每次请求都要创建连接的缺点。但是,响应到达的顺序必须和请求发送的顺序一致,本质上还是没有解决队头阻塞。
HTTP1.1
使用字段Connection
来开启或关闭持续连接,当该字段的值为keep-alive
则为开启,值为close
则为关闭。
Connection: keep-alive
Keep-Alive: time-out=60 //表示这个TCP连接可以保持60秒,可能有max=X,表示这个最多接收X次请求就断开
断点续传
断点续传需要用到几个字段:Range
、If-Range
、Content-Range
、Accept-Ranges
以及Content-Length
。
Range
用于请求头中,指定第一个字节的位置和最后一个字节的位置,一般格式:
Range: bytes=50- //从第50个字节开始到最后一个字节
Range: bytes=-70 //最后的70个字节
Range: bytes=50-100 //从第50字节到100字节
If-Range
:用于请求头中,用于判断实体是否发生改变,必须与Range
配合使用。若实体未被修改,则响应所缺少的那部分;否则,响应整个新的实体。
If-Range: "55dc2dba-14dd5b" //Etag
If-Range: Tue, 25 Aug 2015 08:56:26 GMT //Last-Modified
Content-Range
用于响应头,指定整个实体中的一部分的插入位置,也指示了整个实体的长度。一般格式:
Content-Range: bytes M-N/size //大小为size的文件的第M-N字节范围的内容
Accept-Ranges
:用于响应头中,告诉客户端支持断点传输
Accept-Ranges: bytes //告诉客户端支持断点传输
Accept-Ranges: none //告诉客户端不支持断点传输
Content-Length
:用于响应头中,表示内容长度。
Content-Length: 1900 //文件总大小
断点续传,如果返回文件的一部分,则使用206
状态码;如果返回整个文件,则使用200
响应码。
实例
请求:
GET /123.zip HTTP/1.1
响应:
HTTP/1.1 200 OK
Accept-Ranges: bytes //告诉客户端支持断点传输
Content-Length: 1900 //文件总大小
Last-Modified: Tue, 25 Aug 2015 08:56:26 GMT
ETag: "55dc2dba-14dd5b"
中间停止下载,重新发起请求。
请求:
GET /123.zip HTTP/1.1
Range:bytes=580-
If-Range: "55dc2dba-14dd5b" //Etag
响应:
HTTP/1.1 206 Partial Content
Accept-Ranges: bytes
Content-Type: image/jpeg //文件类型
Content-Length: (1900-580) //长度则不是总长度了,而580到1900共有多少字节。
Content-Range: bytes 580-(1900-1)/1900
Host 头
Host
是 HTTP 1.1
协议中新增的一个请求头,主要用来实现虚拟主机技术。
虚拟主机(virtual hosting)即共享主机(shared web hosting),可以利用虚拟技术把一台完整的服务器分成若干个主机,因此可以在单一主机上运行多个网站或服务。
举个栗子,有一台 ip 地址为 61.135.169.125
的服务器,在这台服务器上部署着谷歌、百度、淘宝的网站。为什么我们访问 https://www.google.com
时,看到的是 Google 的首页而不是百度或者淘宝的首页?原因就是 Host 请求头决定着访问哪个虚拟主机。
缓存控制
HTTP1.0
使用Expire
、Last-Modefied
、Pragma
字段来控制缓存策略,HTTP1.1
增加了ETag
、Cache-Control
字段。
Pragma
字段常用Pragme:no-cache
来关闭缓存,Cache-Control: no-cache
也可以用来关闭缓存。
header压缩
我们知道,HTTP报文是由开始行、首部行、实体主体三部分组成的。 一般而言,实体主体都会经过gzip
压缩,或者本身传输的就是压缩过后的二进制文件(如图片、音频等),但是开始行和首部行多是没有经过任何压缩,而是直接以纯文本的方式进行传输的,随着web功能越来越复杂,请求数量越来越多,随之而来的就是头部的流量越来越多。
因此,HTTP2.0
提出了对请求和响应的头部进行压缩,即不再只是压缩主题部分,这种压缩方式就是HAPCK
。
简单的说,HPACK
使用2个索引表(静态索引表和动态索引表)来把头部映射到索引值,并对不存在的头部使用 huffman
编码,并动态缓存到索引,从而达到压缩头部的效果。
二进制分帧
在应用层(HTTP2.0
)和传输层(TCP)之间增加一个二进制分帧层。在二进制分帧层中, HTTP2.0
会将所有传输的信息分割为更小的消息和帧,并对它们采用二进制格式的编码 ,其中 HTTP1.x
的首部信息会被封装到 HEADER
帧,而相应的 Request Body 则封装到 DATA
帧里面。
帧:HTTP2.0
通信的最小单位,所有帧都共享一个8字节的首部,其中包含帧的长度、类型、标志、还有一个保留位,并且至少有标识出当前帧所属的流的标识符,帧承载着特定类型的数据,如HTTP首部、负荷、等等。
消息:比帧大的通讯单位,是指逻辑上的HTTP消息,比如请求、响应等。由一个或多个帧组成
流:比消息大的通讯单位。是TCP连接中的一个虚拟通道,可以承载双向的消息。每个流都有一个唯一的整数标识符
多路复用
HTTP2.0
通信都在一个 TCP 连接上完成,这个连接可以承载任意数量的双向数据流,相应的每个数据流以消息的形式发送。而消息由一或多个帧组成,这些帧可以乱序发送,然后根据每个帧首部的流标识符重新组装。
服务器推送
HTTP 2.0
新增的一个强大的新功能,就是服务器可以对一个客户端请求发送多个响应。换句话说,除了对最初请求的响应外,服务器还可以额外向客户端推送资源,而无需客户端明确地请求。