# HTTP/1 、HTTP/2 及 HTTP/3
# http1.0与http1.1之间的区别
- 1、缓存策略
http1.0 强缓存;http1.1加入协商缓存。
http1.0的缓存策略主要是依赖header中的If-Modified-Since,Expire(到期)
http1.1的缓存策略要比http1.0略多,例如 Entity tag(实体标签), If-Unmodified-Since, If-Match, If-None-Match等.
- 2、宽带和网络连接优化
加入断点续传。
http1.0中会存在一些性能浪费,比如我们的只需要对象中的一部分,但是每次请求返回的却是整个对象,这无疑造成了性能的损害
http1.1则不然,它可以通过在请求头处设置range头域,就可以返回请求资源的某一部分,也就是返回码为206(Partial Content)的时候,这对于性能优化很有必要.
TIP
这里所谓的请求资源的一部分,也就是大家常说的断点续传
关于断点续传的应用场景,例如用户需要下载一个大文件,最佳的方式是将这个大文件分割成几部分,然后由多个进程同时进行.
这个时候,我们可以在请求头中设置range字段,来规定分割的byte数范围.
而服务端会给客户端返回一个包含着content-range的响应头,来对应相应的分割byte数范围
请求头中:
Range: bytes=0-801 // 一般请求下载整个文件是bytes=0- 或不用这个头 响应头中:
Content-Range: bytes 0-800/801 //801:文件总大小
- 3、新增部分错误通知
http1.1版本新增了24个错误状态响应码,比如
409(Conflict)表示: 请求的资源与当前的状态发生冲突 410(Gone)表示服务器上某个资源被永久性的删除了
- 4、Host头处理:
http1.0中默认每台服务器都绑定唯一的一个IP地址,所以请求消息中url并没有传递主机名,也就是hostname.
http1.1中请求消息和响应消息都支持Host头域,而且,如果我们不传这个字段还会报一个400(bad request)的状态码
这里也介绍下头域的内容:
通用头域:
Cache-Control: 缓存头域 => 常见值为no-cache(不允许缓存,走协商缓存), no-store(无论请求还是响应均不允许缓存), max-age(规定可以客户端可以接受多长生命期的数据)
Keep-Alive: 使得服务端和客户端的链接长时间有效
Date: 信息发送的时间
Host: 请求资源的主机IP和端口号
Range: 请求资源的某一部分
User-Agent: 发出请求的用户的信息(鉴权)
- 5、长连接:
http1.1支持长连接和请求的流水线(pipelining),在一个TCP链接上可以传送多个http请求和响应.这样就不用多次建立和关闭TCP连接了。
# http2.0和http1.x的区别
- 1、http1的解析是基于文本协议的各式解析,而http2.0的协议解析是二进制格式,更加的强大
- 2、多路复用(Mutiplexing) : 一个连接上可以有多个request,且可以随机的混在一起,每个不同的request都有对应的id,服务端可以通过request_id来辨别,大大加快了传输速率
- 3、header压缩: http1.x中的header需要携带大量信息,而且每次都要重复发送。http2.0使用encode来减少传输的header大小,而且客户端和服务端可以各自缓存(cache)一份header filed表,避免了header的重复传输,还可以减少传输的大小。
- 4、服务端推送(server push): 可以通过解析html中的依赖,只能的返回所需的其他文件(css或者js等),而不用再发起一次请求。
# HTTP1.1 的缺陷
- 1、高延迟 — 队头阻塞(Head-Of-Line Blocking) (opens new window)
- 2、无状态特性 — 阻碍交互
- 3、明文传输 — 不安全性
- 4、不支持服务端推送
# 1、高延迟--带来页面加载速度的降低
虽然近年来网络带宽增长非常快,然而我们却并没有看到网络延迟有相应程度的降低。网络延迟问题主要由于队头阻塞(Head-Of-Line Blocking),导致带宽无法被充分利用。
队头阻塞是指当顺序发送的请求序列中的一个请求因为某种原因被阻塞时,在后面排队的所有请求也一并被阻塞,会导致客户端迟迟收不到数据。针对队头阻塞,人们尝试过以下办法来解决:
- (1)、将同一页面的资源分散到不同域名下,提升连接上限
Chrome有个机制,对于同一个域名,默认允许同时建立 6 个 TCP持久连接,使用持久连接时,虽然能公用一个TCP管道,但是在一个管道中同一时刻只能处理一个请求,在当前的请求没有结束之前,其他的请求只能处于阻塞状态。另外如果在同一个域名下同时有10个请求发生,那么其中4个请求会进入排队等待状态,直至进行中的请求完成。
- (2)、合并小文件减少资源数
精灵图,Spriting合并多张小图为一张大图,再用JavaScript或者CSS将小图重新“切割”出来的技术。精灵图,Spriting合并多张小图为一张大图,再用JavaScript或者CSS将小图重新“切割”出来的技术。
- (3)、内联(Inlining)资源
是另外一种防止发送很多小图请求的技巧,将图片的原始数据嵌入在CSS文件里面的URL里,减少网络请求次数。
- (4)、减少请求数量
拼接(Concatenation)将多个体积较小的JavaScript使用webpack等工具打包成1个体积更大的JavaScript文件,但如果其中1个文件的改动就会导致大量数据被重新下载多个文件。
# 2、无状态特性--带来的巨大HTTP头部
无状态是指协议对于连接状态没有记忆能力。纯净的 HTTP 是没有 cookie 等机制的,每一个连接都是一个新的连接。
由于报文Header一般会携带"User Agent""Cookie""Accept""Server"等许多固定的头字段(如下图),多达几百字节甚至上千字节,但Body却经常只有几十字节(比如GET请求、204/301/304响应),成了不折不扣的“大头儿子”。Header里携带的内容过大,在一定程度上增加了传输的成本。更要命的是,请求响应报文里有大量字段值都是重复的,非常浪费。
# 3、明文传输--带来的不安全性
HTTP/1.1在传输数据时,所有传输的内容都是明文,客户端和服务器端都无法验证对方的身份,这在一定程度上无法保证数据的安全性。
# 4、不支持服务器推送消息
# HTTP/2
# SPDY 协议
上面我们提到,由于HTTP/1.x的缺陷,我们会引入雪碧图、将小图内联、使用多个域名等等的方式来提高性能。不过这些优化都绕开了协议,直到2009年,谷歌公开了自行研发的 SPDY 协议,主要解决HTTP/1.1效率不高的问题。谷歌推出SPDY,才算是正式改造HTTP协议本身。降低延迟,压缩header等等,SPDY的实践证明了这些优化的效果,也最终带来HTTP/2的诞生。
HTTP/1.1有两个主要的缺点: 安全不足和性能不高,由于背负着 HTTP/1.x 庞大的历史包袱,所以协议的修改,兼容性是首要考虑的目标,否则就会破坏互联网上无数现有的资产。如上图所示,SPDY位于HTTP之下,TCP和SSL之上,这样可以轻松兼容老版本的HTTP协议(将HTTP1.x的内容封装成一种新的frame格式),同时可以使用已有的SSL功能。
SPDY 协议在Chrome浏览器上证明可行以后,就被当作 HTTP/2 的基础,主要特性都在 HTTP/2 之中得到继承。
# HTTP/2 简介
2015年,HTTP/2 发布。HTTP/2是现行HTTP协议(HTTP/1.x)的替代,但它不是重写,HTTP方法/状态码/语义都与HTTP/1.x一样。HTTP/2基于SPDY,专注于性能,最大的一个目标是在用户和网站间只用一个连接(connection) 。从目前的情况来看,国内外一些排名靠前的站点基本都实现了HTTP/2的部署,使用HTTP/2能带来20%~60%的效率提升。 HTTP/2由两个规范(Specification)组成:
- Hypertext Transfer Protocol version 2 - RFC7540
- HPACK - Header Compression for HTTP/2 - RFC7541
# HTTP/2 新特性
# 1、二进制传输
HTTP/2传输数据量的大幅减少,主要有两个原因:以二进制方式传输和Header 压缩。我们先来介绍二进制传输,HTTP/2 采用二进制格式传输数据,而非HTTP/1.x 里纯文本形式的报文 ,二进制协议解析起来更高效。HTTP/2 将请求和响应数据分割为更小的帧,并且它们采用二进制编码。
它把TCP协议的部分特性挪到了应用层,把原来的"Header+Body"的消息"打散"为数个小片的二进制"帧"(Frame),用"HEADERS"帧存放头数据、"DATA"帧存放实体数据。HTP/2数据分帧后"Header+Body"的报文结构就完全消失了,协议看到的只是一个个的"碎片"。
HTTP/2 中,同域名下所有通信都在单个连接上完成,该连接可以承载任意数量的双向数据流。每个数据流都以消息的形式发送,而消息又由一个或多个帧组成。多个帧之间可以乱序发送,根据帧首部的流标识可以重新组装。
# 2、Header 压缩
HTTP/2并没有使用传统的压缩算法,而是开发了专门的"HPACK”算法,在客户端和服务器两端建立“字典”,用索引号表示重复的字符串,还采用哈夫曼编码来压缩整数和字符串,可以达到50%~90%的高压缩率。
具体来说:
在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键-值对,对于相同的数据,不再通过每次请求和响应发送; 首部表在HTTP/2的连接存续期内始终存在,由客户端和服务器共同渐进地更新; 每个新的首部键-值对要么被追加到当前表的末尾,要么替换表中之前的值
# 3、多路复用
在 HTTP/2 中引入了多路复用的技术。多路复用很好的解决了浏览器限制同一个域名下的请求数量的问题,同时也接更容易实现全速传输,毕竟新开一个 TCP 连接都需要慢慢提升传输速度。
在 HTTP/2 中,有了二进制分帧之后,HTTP /2 不再依赖 TCP 链接去实现多流并行了,在 HTTP/2中:
- 同域名下所有通信都在单个连接上完成。
- 单个连接可以承载任意数量的双向数据流。
- 数据流以消息的形式发送,而消息又由一个或多个帧组成,多个帧之间可以乱序发送,因为根据帧首部的流标识可以重新组装。
这一特性,使性能有了极大提升:
- 同个域名只需要占用一个 TCP 连接,使用一个连接并行发送多个请求和响应,这样整个页面资源的下载过程只需要一次慢启动,同时也避免了多个TCP连接竞争带宽所带来的问题。
- 并行交错地发送多个请求/响应,请求/响应之间互不影响。
- 在HTTP/2中,每个请求都可以带一个31bit的优先值,0表示最高优先级, 数值越大优先级越低。有了这个优先值,客户端和服务器就可以在处理不同的流时采取不同的策略,以最优的方式发送流、消息和帧。
# 4、Server Push
HTTP2还在一定程度上改变了传统的“请求-应答”工作模式,服务器不再是完全被动地响应请求,也可以新建“流”主动向客户端发送消息。比如,在浏览器刚请求HTML的时候就提前把可能会用到的JS、CSS文件发给客户端,减少等待的延迟,这被称为"服务器推送"( Server Push,也叫 Cache push
另外需要补充的是,服务端可以主动推送,客户端也有权利选择是否接收。如果服务端推送的资源已经被浏览器缓存过,浏览器可以通过发送RST_STREAM帧来拒收。主动推送也遵守同源策略,换句话说,服务器不能随便将第三方资源推送给客户端,而必须是经过双方确认才行。
# 5、提高安全性
出于兼容的考虑,HTTP/2延续了HTTP/1的“明文”特点,可以像以前一样使用明文传输数据,不强制使用加密通信,不过格式还是二进制,只是不需要解密。
但由于HTTPS已经是大势所趋,而且主流的浏览器Chrome、Firefox等都公开宣布只支持加密的HTTP/2,所以“事实上”的HTTP/2是加密的。也就是说,互联网上通常所能见到的HTTP/2都是使用"https”协议名,跑在TLS上面。HTTP/2协议定义了两个字符串标识符:“h2"表示加密的HTTP/2,“h2c”表示明文的HTTP/2。
# HTTP/2 的缺点
虽然 HTTP/2 解决了很多之前旧版本的问题,但是它还是存在一个巨大的问题,主要是底层支撑的 TCP 协议造成的。HTTP/2的缺点主要有以下几点:
- 1、TCP 以及 TCP+TLS 建立连接的延时;
- 2、TCP 的队头阻塞并没有彻底解决;
- 3、多路复用导致服务器压力上升;
- 4、多路复用容易 Timeout。
# 1、建连延时
HTTP/2都是使用TCP协议来传输的,而如果使用HTTPS的话,还需要使用TLS协议进行安全传输,而使用TLS也需要一个握手过程,这样就需要有两个握手延迟过程:
- (1)、*在建立TCP连接的时候,需要和服务器进行三次握手来确认连接成功,即需要消耗完 1.5 个 RTT 之后才能进行数据传输。
- (2)、*进行TLS连接,TLS有两个版本——TLS1.2和TLS1.3,每个版本建立连接所花的时间不同,大致是需要1~2个RTT。
总之,在传输数据之前,我们需要花掉 3~4 个 RTT。
RTT(Round-Trip Time): 往返时延。表示从发送端发送数据开始,到发送端收到来自接收端的确认(接收端收到数据后便立即发送确认),总共经历的时延。
# 2、队头阻塞没有彻底解决
上文我们提到在HTTP/2中,多个请求是跑在一个TCP管道中的。但当出现了丢包时,HTTP/2 的表现反倒不如 HTTP/1 了。因为TCP为了保证可靠传输,有个特别的“丢包重传”机制,丢失的包必须要等待重新传输确认,HTTP/2出现丢包时,整个 TCP 都要开始等待重传,那么就会阻塞该TCP连接中的所有请求(如下图)。而对于 HTTP/1.1 来说,可以开启多个 TCP 连接,出现这种情况反到只会影响其中一个连接,剩余的 TCP 连接还可以正常传输数据。
RTO:英文全称是 Retransmission TimeOut,即重传超时时间; RTO 是一个动态值,会根据网络的改变而改变。RTO 是根据给定连接的往返时间 RTT 计算出来的。 接收方返回的 ack 是希望收到的下一组包的序列号。 可能就会有人考虑为什么不直接去修改 TCP 协议?其实这已经是一件不可能完成的任务了。因为 TCP 存在的时间实在太长,已经充斥在各种设备中,并且这个协议是由操作系统实现的,更新起来不大现实。
# 3、多路复用导致服务器压力上升
多路复用没有限制同时请求数。请求的平均数量与往常相同,但实际会有许多请求的短暂爆发,导致瞬时 QPS 暴增。
# 4、多路复用容易 Timeout
大批量的请求同时发送,由于 HTTP2 连接内存在多个并行的流,而网络带宽和服务器资源有限,每个流的资源会被稀释,虽然它们开始时间相差更短,但却都可能超时。 即使是使用 Nginx 这样的负载均衡器,想正确进行节流也可能很棘手。 其次,就算你向应用程序引入或调整排队机制,但一次能处理的连接也是有限的。如果对请求进行排队,还要注意在响应超时后丢弃请求,以避免浪费不必要的资源
# HTTP/3 新特性
# 1、HTTP/3简介
Google 在推SPDY的时候就已经意识到了这些问题,于是就另起炉灶搞了一个基于 UDP 协议的“QUIC”协议,让HTTP跑在QUIC上而不是TCP上。而这个“HTTP over QUIC”就是HTTP协议的下一个大版本,HTTP/3。它在HTTP/2的基础上又实现了质的飞跃,真正“完美”地解决了“队头阻塞”问题。
QUIC 虽然基于 UDP,但是在原本的基础上新增了很多功能,接下来我们重点介绍几个QUIC新功能。不过HTTP/3目前还处于草案阶段,正式发布前可能会有变动,所以本文尽量不涉及那些不稳定的细节。
# 2、QUIC新功能
上面我们提到QUIC基于UDP,而UDP是“无连接”的,根本就不需要“握手”和“挥手”,所以就比TCP来得快。此外QUIC也实现了可靠传输,保证数据一定能够抵达目的地。它还引入了类似HTTP/2的“流”和“多路复用”,单个“流"是有序的,可能会因为丢包而阻塞,但其他“流”不会受到影响。具体来说QUIC协议有以下特点:
- (1)、实现了类似TCP的流量控制、传输可靠性的功能
虽然UDP不提供可靠性的传输,但QUIC在UDP的基础之上增加了一层来保证数据可靠性传输。它提供了数据包重传、拥塞控制以及其他一些TCP中存在的特性。
QUIC 协议到底改进在哪些方面呢?主要有如下几点:
1、可插拔 — 应用程序层面就能实现不同的拥塞控制算法。
2、单调递增的 Packet Number — 使用 Packet Number 代替了 TCP 的 seq。
3、不允许 Reneging — 一个 Packet 只要被 Ack,就认为它一定被正确接收。
4、前向纠错(FEC)
5、更多的 Ack 块和增加 Ack Delay 时间。
6、基于 stream 和 connection 级别的流量控制。
(2)、实现了快速握手功能
由于QUIC是基于UDP的,所以QUIC可以实现使用0-RTT或者1-RTT来建立连接,这意味着QUIC可以用最快的速度来发送和接收数据,这样可以大大提升首次打开页面的速度。0RTT 建连可以说是 QUIC 相比 HTTP2 最大的性能优势。
- (3)、集成了TLS加密功能
目前QUIC使用的是TLS1.3,相较于早期版本TLS1.3有更多的优点,其中最重要的一点是减少了握手所花费的RTT个数。
在完全握手情况下,需要 1-RTT 建立连接。 TLS1.3 恢复会话可以直接发送加密后的应用数据,不需要额外的 TLS 握手,也就是 0-RTT。
但是 TLS1.3 也并不完美。TLS 1.3 的 0-RTT 无法保证前向安全性(Forward secrecy)。简单讲就是,如果当攻击者通过某种手段获取到了 Session Ticket Key,那么该攻击者可以解密以前的加密数据。
要缓解该问题可以通过设置使得与 Session Ticket Key 相关的 DH 静态参数在短时间内过期(一般几个小时)。
- (4)、多路复用,彻底解决TCP中队头阻塞的问题
和TCP不同,QUIC实现了在同一物理连接上可以有多个独立的逻辑数据流(如下图)。实现了数据流的单独传输,就解决了TCP中队头阻塞的问题。
- (5)、连接迁移
TCP 是按照 4 要素(客户端 IP、端口, 服务器 IP、端口)确定一个连接的。而 QUIC 则是让客户端生成一个 Connection ID (64 位)来区别不同连接。只要 Connection ID 不变,连接就不需要重新建立,即便是客户端的网络发生变化。由于迁移客户端继续使用相同的会话密钥来加密和解密数据包,QUIC 还提供了迁移客户端的自动加密验证。
# 总结
- 1、HTTP/1.1有两个主要的缺点:安全不足和性能不高。
- 2、HTTP/2完全兼容HTTP/1,是“更安全的HTTP、更快的HTTPS",二进制传输、头部压缩、多路复用、服务器推送等技术可以充分利用带宽,降低延迟,从而大幅度提高上网体验;
- 3、QUIC 基于 UDP 实现,是 HTTP/3 中的底层支撑协议,该协议基于 UDP,又取了 TCP 中的精华,实现了即快又可靠的协议。