HTTP是基于TCP的一个应用,本文简要对比一下各主流HTTP协议的区别。
一、各主流版本区别
主流版本如下:
- HTTP 0.9
- HTTP 1.1
- HTTP 2.0
1.1 HTTP 0.9
HTTP 1.0 默认是短链接,即Keep-Alive为false
,所有的请求自然也无法复用,因此每次请求都需要经过TCP的三次握手、四次挥手,效率低下。
只支持GET请求。
1.2 HTTP 1.1
1.2.1 ‘长’连接
HTTP 1.1 默认开启了连接保持,即Keep-Alive为true
,因此连接自创建之初会保留一段时间,直到timeout或者客户端/服务端任意一方想要通过connection:close
进行关闭连接,针对HTTPkeep-alive
的设置,请移步至此:https://devdocs.io/http/headers/keep-alive。
1.2.2 分包传输
提供了Transfer-Encoding
header,支持信息payload分包传输,那么关于分包传输,请求接收端需要关注两个参数:chunk-size
、chunk-data
。一个Data会被拆分成一系列的Chunk发送,当服务接受端接到一个包的chunk-size为0时,代表所有的Chunk已经传输完毕。
chunk = chunk-size [ chunk-ext ] CRLF
chunk-data CRLF
请移步至此:https://devdocs.io/http/rfc9112#section-7
1.2.3 Pipelining
HTTP支持管道方式传输,进一步优化了请求速度,多个请求可以“并行”传输,而不再像HTTP0.9那样:前一个请求有响应之后才能发送下一个请求(严格串型)。
Pipelining最大的缺陷在于:原本客户端的串型转移到了服务器上。客户端并行发送完请求之后,在收到服务端多个响应时,因为不知道如何将多个响应给到对应的请求,因此,这就不得不让服务端来控制响应的发送顺序了。
举例:Request 同时发送JS文件与CSS文件请求,需要服务端先返回JS文件再返回CSS文件,就算CSS文件先处理好也无法发送。
备注:Pipelining在很多浏览器与服务端默认不支持。我猜测其确实提高了客户端的并发,但是加重了服务端的处理压力,最终的并发可能还是会受限于服务端。
1.3 HTTP 2.0
一个重要的前提:HTTP2只能应用在HTTPS协议中。
1.3.1 二进数据帧
原本的HTTP文本形式都会变成二进制格式传输,原本的传输内容也会被切割成数据帧,Header部分形成Header数据帧,Body部分形成Payload数据帧,而这些数据帧中都有一个非常重要的字段流标识符,这也为多路复用打下基础,也因此环节了HTTP对头阻塞的现象。
1.3.2 多路复用
HTTP2.0与HTTP1.1的Pipelining非常相似,但是HTTP2.0缓解了Pipelining中的对头阻塞的问题,进一步优化了响应速度。
HTTP2.0可以使用一个TCP连接足矣。
当有多个请求/响应时,客户端/服务端会将每个请求/响应都拆分成多个数据帧,并且进行流标识,随后将所有数据帧并行发送给对端(并行发送,不在乎顺序,这是与Pipelining最大的差别)。
当这些数据帧到达对端时,对端通过流标识符进行顺序重组即可。
但是多路复用并没有完全解决队头阻塞问题,因为到达的消息仍然可能存在丢包的情况,比如服务端并行的发送给客户端一波数据帧,但是在TCP层面第一个帧就传输丢失了,那么此时只能依赖TCP的重传机制了。因此HTTP2.0多路复用只解决了HTTP层面的队头阻塞,TCP层面仍然会有,除非TCP也做一次大的改革,也利用HTTP2.0那样,在每一个数据库上打上流标识符。
1.3.3 Header压缩
头部压缩依赖的是静态表和动态表以及哈夫曼压缩算法。
即:Header 名称通过静态表与动态表的码表表示,而Value则是通过哈夫曼算法进行压缩。
因此大大减少了带宽。
具体见:https://datatracker.ietf.org/doc/html/rfc7540#page-14
1.3.4 服务端推送
这里的推送并不是我们常说的WebSocket、SSE协议哈。
这里指,当前端向后端索要文件时,譬如JS文件,那么后端可以将JS、CSS、图片等信息都返回给客户端,减少请求次数。