HTTP版本差异
HTTP 1.0
1.0的HTTP是一个无连接、无状态的应用层协议。因此客户端每次请求服务器都需要建立一个TCP链接,服务器处理完TCP立即断开(无连接),服务器也不会记录每次的请求(无状态)。
无状态可以使用
Cookie
与Session
来实现身份认证与状态记录(状态化)。
问题:
无法实现连接复用
每次发送请求后,都需要进行一次TCP连接,TCP的连接与释放过程消耗很多资源,这种无连接特性会导致网络复用率变低。
队头阻塞
由于HTTP 1.0规定下一个请求必须在前一个请求响应到达之前才能发送,假设前一个请求响应一直不到达,那么下一个请求将一直阻塞。
HTTP 1.1
长连接
HTTP 1.1解决了连接复用的问题。HTTP 1.1增加了Connection
字段,通过设置Keep-Alive使得HTTP连接能够连接不断,避免客户端与服务器多次建立与释放TCP连接,提高了网络的复用率。
当客户端需要关闭连接的时候,可以在请求头的Connection
设为false
告知服务器关闭。
管道化
基于长连接实现,客户端能够发送多个请求,但是服务器必须按照请求的顺序依次回应相应的结果,即:让队列从客户端的请求队列迁移到了服务器的响应队列,但是仍然没有解决队头阻塞的问题。
HTTP 2.0
二进制分帧
HTTP 2.0通过在应用层与传输层之间增加了一个二进制分帧层,突破了HTTP 1.0的性能限制,改进了传输性能。
多路复用
- 流:已建立连接上的双向自己流。
- 消息:与逻辑消息对应的完整的一系列数据帧。
- 帧(frame):HTTP 2.0通信的最小单位,每个帧包含头部,至少也会标识出当前所属的流(stream_id)
每个数据流以消息的形式发送,而消息由一个或者多个帧组成。帧可以乱序发送,然后依赖流标识符重新封装。
并且HTTP 2.0的数据流可以设置优先级与依赖。
头部压缩
在HTTP 1.X中,头部源数据都是以纯文本的形式发送的,会给每个请求头增加较多字节的负荷(Cookie),HTTP 2.0要求客户端与服务器都缓存一张Header_Files
表,将Header
进行编码压缩,避免了重复Header
的传输,减小了传输的负荷。
服务器推送
即客户端发送一次请求,服务器会主动将所需要的资源一次性推送给客户端。eg: 客户端请求一个index.html资源,服务器将在一次请求内将所有所需的index.css, index.js等资源返回给客户。
这里的问题在于当用户误触到某个链接的时候,由于服务器推送机制,用户会一次性获取非常多不必要的资源,这种可能会造成DDoS攻击的实现。
HTTP 3.0
HTTP 2.0成功解决了头部阻塞的问题,但是这里解决的只是应用层的头部阻塞,在传输层的TCP中,出现丢包的情况整个TCP都要等待重传,即传输层的头部阻塞并没有被解决,而修改TCP协议是不可能的(TCP协议由操作系统负责)。
整合
HTTP 2.0默认使用TLS加密,那么除了TCP握手外,还需要建立TLS握手,这样需要消耗非常多的资源(即使TLS 1.3较TLS 1.2已做了优化)。在HTTP 3.0中,TCP握手与TLS握手整合到了一起。即0-RTT连接。
QUIC + UDP
QUIC基于UDP,一个连接上的多个流没有依赖,即使丢包只需要重新发送丢失的包即可,不需要重传整个连接,实现了多路复用。
QUIC的帧中包含了Connection_Id
字段,QUIC是通过该段识别连接的,而TCP是基于IP识别连接的,那么当网络环境变化的时候,Connection_Id
并不会改变,能够迅速实现重连,能够提供更好的移动端表现。
QUIC除了部分报文外,报文头部与报文BODY都经过加密,有效降低了安全风险。
向前纠错,每个数据包除了它本身的内容之外还包括了其他数据包的数据,因此少量的丢包可以通过其他包的冗余数据直接组装而无需重传。