前言
HTTP/1.1已经能满足互联网的大部分需求,但其实HTTP/1.1还有很大的可优化空间,所以HTTP/2就出场了。
需要注意的是HTTP/2并不是HTTP/2.0,因为HTTP/2 工作组认为以前的“HTTP/1.0”“HTTP/1.1”造成了很多的混乱和误解。所以就决定 HTTP 协议不再使用小版本号只使用大版本号。
HTTP/2新特性
头部压缩
为何要进行头部压缩
在HTTP/1中我们可以用字段“Content-Encoding”指定 body 的编码方式来压缩body内容节约带宽。
但其实开发中比较常见的一些情况例如GET 请求、204/301/304 响应,body通常只有几十字节,而Header一般会携带,“User Agent”“Cookie”“Accept”“Server”等许多固定的头字段,多达几百字节甚至上千字节。
成千上万的请求响应报文里有很多字段值都是重复的,非常浪费,“长尾效应”导致大量带宽消耗在了这些冗余度极高的数据上。
所以HTTP/2 把“头部压缩”作为性能改进的一个重点。
如何进行头部压缩
HTTP/2 开发了专门的“HPACK”算法,在客户端和服务器两端建立“字典”,用索引号表示重复的字符串,还釆用哈夫曼编码来压缩整数和字符串,可以达到 50%~90% 的高压缩率。
二进制格式 & 多路复用
为何要用二进制格式
HTTP/1使用的是纯文本报文,它的优点是“一目了然”,用最简单的工具就可以开发调试,非常方便。
但在计算机解析时原来使用纯文本的时候容易出现多义性,比如大小写、空白字符、回车换行、多字少字等等,程序在处理时必须用复杂的状态机,效率低,还麻烦。
而二进制里只有“0”和“1”,可以严格规定字段大小、顺序、标志位等格式,解析起来没有歧义,实现简单,而且体积小、速度快,做到“内部提效”。
二进制格式具体实现
将之前HTTP/1的“Header+Body”的消息“打散”为数个小片的二进制“帧”,用“HEADERS”帧存放头数据、“DATA”帧存放实体数据。
这些二进制“帧通过”流“传输到目的地,“流”是HTTP/2的一个概念,你可以把它想象成是一个虚拟的“数据流”,在里面流动的是一串有先后顺序的数据帧,这些数据帧按照次序组装起来就是 HTTP/1 里的请求报文和响应报文。
因为“流”是虚拟的,实际上并不存在,所以 HTTP/2 就可以在一个 TCP 连接上用“流”同时发送多个“碎片化”的消息,这就是常说的“多路复用”——多个往返通信都复用一个连接来处理。
在“流”的层面上看,消息是一些有序的“帧”序列,而在“连接”的层面上看,消息却是乱序收发的“帧”。多个请求 / 响应之间没有了顺序关系,不需要排队等待,也就不会再出现“队头阻塞”问题,降低了延迟,大幅度提高了连接的利用率。HTTP/2 还添加了一些控制帧来管理虚拟的“流”,实现了优先级和流量控制。
服务器推送
HTTP/2 还在一定程度上改变了传统的“请求 - 应答”工作模式,服务器不再是完全被动地响应请求,也可以新建“流”主动向客户端发送消息。比如,在浏览器刚请求 HTML 的时候就提前把可能会用到的 JS、CSS 文件发给客户端,减少等待的延迟,这被称为“服务器推送”。
Nginx设置服务器推送
location / {
http2_push /style.css
http2_push /test.png
}
强化安全
通常 HTTP/2 是加密的。也就是说,互联网上通常所能见到的 HTTP/2 都是使用“https”协议名,跑在 TLS 上面。
为了区分“加密”和“明文”这两个不同的版本,HTTP/2 协议定义了两个字符串标识符:“h2”表示加密的 HTTP/2,“h2c”表示明文的 HTTP/2,多出的那个字母“c”的意思是“clear text”。
HTTP/2的缺点
- 在移动网络中发生 IP 地址切换的时候,下层的 TCP 必须重新建连,要再次“握手”,经历“慢启动”,而且之前连接里积累的 HPACK 字典也都消失了,必须重头开始计算,导致带宽浪费和时延。
- HTTP/2 对一个域名只开一个连接,所以一旦这个连接出问题,那么整个网站的体验也就变差了。
如何配置HTTP/2
在基于HTTPS的基础上用Nginx配置HTTP/2
server {
// 表示在 443 端口上开启了 SSL 加密,然后再启用 HTTP/2
listen 443 ssl http2;
server_name www.xxx.net;
ssl_certificate xxx.crt;
ssl_certificate_key xxx.key;
浏览器是如何得知服务器是使用HTTP/2通信的呢?
客户端在发起连接握手的时候,后面会带上一个“ALPN”扩展,里面按照优先顺序列出客户端支持的应用协议。如下图所示,最优先的是“h2”,其次是“http/1.1”。服务器看到 ALPN 扩展以后就可以从列表里选择一种应用协议,在回应里也带上“ALPN”扩展,告诉客户端服务器决定使用的是哪一种。因为我们在 Nginx 配置里使用了 HTTP/2 协议,所以在这里它选择的就是“h2”。
HTTP/3展望
HTTP/2没有解决的问题
队头阻塞
在 HTTP/2 把多个“请求 - 响应”分解成流,交给 TCP 后,TCP 会再拆成更小的包依次发送。
假如客户端用 TCP 发送了三个包,但服务器所在的操作系统只收到了后两个包,第一个包丢了。这时TCP会怎么处理?
TCP 为了保证可靠传输,有个特别的“丢包重传”机制,丢失的包必须要等待重新传输确认,其他的包即使已经收到了,也只能放在缓冲区里,上层的应用拿不出来,只能“干着急”。
所以HTTP/3的新特性就出来了。
HTTP/3新特性
HTTP/3本质上是“HTTP over QUIC”。
什么是QUIC协议呢,QUIC是传输层协议,采用了UDP,因为 UDP 是无序的,包之间没有依赖关系,所以就从根本上解决了“队头阻塞”。并且把 TCP 的那一套连接管理、拥塞窗口、流量控制等“搬”了过来,“去其糟粕,取其精华”,打造出了一个全新的可靠传输协议,可以认为是“新时代的 TCP”。
QUIC的特点:
- QUIC 基于 UDP,而 UDP 是“无连接”的,根本就不需要“握手”和“挥手”,所以连接速度比 TCP 快。
- QUIC 基于 UDP 实现了可靠传输,保证数据一定能够抵达目的地。沿用了 HTTP/2 的“流”和“多路复用”,单个“流”是有序的,可能会因为丢包而阻塞,但其他“流”不会受到影响。
- QUIC 全面采用加密通信
最后
感谢大家阅读,如有问题欢迎纠正!