前言
作为一只前端开发?,HTTP是我们知识地图里面必不可少的一部分,也是面试必问知识点。HTTP2号称可以让我们的应用更快、更简单、更稳定,它完美解决了1.1版本的诸多问题,本文和大家一起聊聊HTTP2的改进点。
HTTP发展史
正式讲HTTP2之前我们先讲一下HTTP的发展史。
- HTTP/0.9 - 单行协议
HTTP于1990年问世,那时候HTTP非常简单:只支持GET方法;没有首部;只能获取纯文本。 - HTTP/1.0 - 搭建协议的框架
1996年,HTTP正式被作为标准公布,版本为HTTP/1.0。1.0版本增加了首部、状态码、权限、缓存、长连接(默认短连接)等规范,可以说搭建了协议的基本框架。 - HTTP/1.1 - 进一步完善
1997年,1.1版本接踵而至。1.1版本的重大改进在于默认长连接;强制客户端提供Host首部;管线化;Cache-Control、ETag等缓存的相关扩展。
目前存在的问题
现在我们先不聊HTTP2, 看一下HTTP发展到1.1存在有哪些问题:
- 线头阻塞:TCP连接上只能发送一个请求,前面的请求未完成前,后续的请求都在排队等待。
- 多个TCP连接
虽然HTTP/1.1管线化可以支持请求并发,但是浏览器很难实现,chrome、firefox等都禁用了管线化。所以1.1版本请求并发依赖于多个TCP连接,建立TCP连接成本很高,还会存在慢启动的问题。 - 头部冗余,采用文本格式
HTTP/1.X版本是采用文本格式,首部未压缩,而且每一个请求都会带上cookie、user-agent等完全相同的首部。 - 客户端需要主动请求
HTTP/2.0的时代来了
先来一个demo感受一下吊炸天的HTTP/2.0,这个demo是加载379张图片,来对比HTTP/1.1和HTTP/2.0的性能。
![](https://i-blog.csdnimg.cn/blog_migrate/6e1d0c6addab58293a3302b1b07dbb1e.png)
理论上HTTP/2.0会比HTTP/1.1有一倍多的性能提升,弱网环境下,性能提升会更加明显。 下面两张图是我在设置网络在fast 3G 和slow 3G的性能对比。
![](https://i-blog.csdnimg.cn/blog_migrate/9c690f8207da0d4d17a575da3ec7d968.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f940e7230a5a63b08f0b1cf1299e184a.png)
二进制分帧层
HTTP2性能提升的核心就在于二进制分帧层。HTTP2是二进制协议,他采用二进制格式传输数据而不是1.x的文本格式。
![](https://i-blog.csdnimg.cn/blog_migrate/a42cf15422efcea222d6bee7ee9ced5b.png)
这里我们来提三个概念。
- 流(Stream):已建立的TCP连接上的双向字节流,可以承载一个或多个消息。
- 消息(Message):一个完整的HTTP请求或响应,由一个或多个帧组成。特定消息的帧在同一个流上发送,这意味着一个HTTP请求或响应只能在一个流上发送。
- 帧(Frame):通信的基本单位。
一个TCP连接上可以有任意数量的流。
多路复用
上面提到HTTP/1.1的线头阻塞和多个TCP连接的问题,HTTP2的多路复用完美解决。HTTP2让所有的通信都在一个TCP连接上完成,真正实现了请求的并发。我们来看一下HTTP2具体是怎么实现的:
![](https://i-blog.csdnimg.cn/blog_migrate/62c77ec4af243af5d0a1b0c31d29aa29.png)
![](https://i-blog.csdnimg.cn/blog_migrate/0ab87a8bcd63076a13f12be77bf383a5.png)
这里例子我们能很直观的看到就是多路复用起到的优化作用。因为HTTP2 实现了请求并发,后面的请求不用再等待,加载时长当然少了很多。截一张HTTP2的图片加载耗时详情来看看(要看比较靠后的请求):
![](https://i-blog.csdnimg.cn/blog_migrate/d644e9aa05759595786e2ad43865168a.png)
头部压缩
头部压缩也是HTTP2的一大亮点。在1.X版本中,首部用文本格式传输,通常会给每个传输增加500-800字节的开销。现在打开一个网页上百个请求已是常态,而每个请求带的一些首部字段都是相同的,例如cookie、user-agent等。HTTP2为此采用HPACK压缩格式来压缩首部。头部压缩需要在浏览器和服务器端之间:
- 维护一份相同的静态字典,包含常见的头部名称,以及常见的头部名称和值的组合
- 维护一份相同的动态字典,可以动态的添加内容
- 通过静态Huffman编码对传输的首部字段进行编码
HTTP2的静态字典是长这个样子的(只截取了部分,完整表格在这里):
![](https://i-blog.csdnimg.cn/blog_migrate/ad3bbea39a6c6206be17a901da3e7c14.png)
第一次传输过user-agent 之后呢,浏览器和服务器端就会把它添加到自己的动态字典中。后续传输就可以传输索引了,一个字节搞定。
我们用WireShark来抓包验证一下:
HTTP2目前都是HTTPS的请求,WireShark对HTTPS网站抓包解密请参考这里。
- 首次传输user-agent和第二次传输user-agent
![](https://i-blog.csdnimg.cn/blog_migrate/2733d2e6994d666ee82612139ff1f238.png)
- HPACK的首部压缩力度
![](https://i-blog.csdnimg.cn/blog_migrate/9d7b135edaa9833799d1ba28cff17bfd.png)
![](https://i-blog.csdnimg.cn/blog_migrate/755a49daa3a1a58037d4f378c1426cce.png)
服务器端推送
服务器端推送使得服务器可以预测客户端需要的资源,主动推送到客户端。
例如:客户端请求index.html,服务器端能够额外推送script.js和style.css。 实现原理就是客户端发出页面请求时,服务器端能够分析这个页面所依赖的其他资源,主动推送到客户端的缓存,当客户端收到原始网页的请求时,它需要的资源已经位于缓存。
针对每一个希望发送的资源,服务器会发送一个PUSH_PROMISE帧,客户端可以通过发送RST_STREAM帧来拒绝推送(当资源已经位于缓存)。这一步的操作先于父响应(index.html),客户端了解到服务器端打算推送哪些资源,就不会再为这些资源创建重复请求。当客户端收到index.html的响应时,script.js和style.css已经位于缓存。
想要搭一个HTTP2服务器的话推荐node,很简单。链接
参考文章
结语
简单讲了HTTP2相比1.1版本的重要改进点,感受了一下h2的强大。还有一些流优先化等特性文中未涉及,感兴趣的可以在参考文章中看看。如有错误,恳请指正!
@Author:小夭yao爱吃糖糖糖
作者:黑金团队/小夭yao爱吃糖糖糖
链接:https://juejin.im/post/5c0ce870f265da61171c8c66#heading-4
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。