转载自AlloyTeam:http://www.alloyteam.com/2015/03/http2-0-di-qi-miao-ri-chang/

“多年没见,你的女神后来什么样了”晨伯总是这么八卦我的女神,而不是我。 “我给你一个表情,你自己体会一下” “你先写个小页面给我看看吧,我指导一下你吧。”晨伯一幅很吊的样子。 但是这样的小case当然难不了我,虽然多年没碰web,但是我当年可以是AlloyTeam的成员啊。很快我就啪啪啪地完成了页面。晨伯看完我写的页面,一幅“我可是有女朋友的男人”的表情,感叹了一句“现在是HTTP2.0的时代啦,给你普及一下知识点”。

HTTP2.0性能增强的核心:二进制分帧

HTTP 2.0最大的特点: 不会改动HTTP 的语义,HTTP 方法、状态码、URI 及首部字段,等等这些核心概念上一如往常,却能致力于突破上一代标准的性能限制,改进传输性能,实现低延迟和高吞吐量。而之所以叫2.0,是在于新增的二进制分帧层。 既然又要保证HTTP的各种动词,方法,首部都不受影响,那就需要在应用层(HTTP2.0)和传输层(TCP or UDP)之间增加一个二进制分帧层。 在二进制分帧层上, HTTP 2.0 会将所有传输的信息分割为更小的消息和帧,并对它们采用二进制格式的编码 ,其中HTTP1.x的首部信息会被封装到Headers帧,而我们的request body则封装到Data帧里面。

http2.0

然后,HTTP 2.0 通信都在一个连接上完成,这个连接可以承载任意数量的双向数据流。相应地,每个数据流以消息的形式发送,而消息由一或多个帧组成,这些帧可以乱序发送,然后再根据每个帧首部的流标识符重新组装。

当他侃侃而谈的时候,大概是这个样子的,你们也来感受一下。

“听起来好屌的样子,但是那样,所有的二进制帧都会带上Headers帧,这是多大的数据冗余传送啊,性能会多….”我疑问道。 “还没讲完呢,插什么嘴!”(哎呀我差!我这么帅,可别打脸啊。)

HTTP2.0 首部压缩

HTTP 2.0 在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键-值对,对于相同的数据,不再通过每次请求和响应发送;通信期间几乎不会改变的通用键-值对(用户代理、可接受的媒体类型,等等)只 需发送一次。事实上,如果请求中不包含首部(例如对同一资源的轮询请求),那么 首部开销就是零字节。此时所有首部都自动使用之前请求发送的首部。 如果首部发生变化了,那么只需要发送变化了数据在Headers帧里面,新增或修改的首部帧会被追加到“首部表”。首部表在 HTTP 2.0 的连接存续期内始终存在,由客户端和服务器共同渐进地更新 。

“好了,现在你倒是给我解释一下,这里使用自动化合并文件和Sprite合图是什么回事?”晨伯不解 “本质上,当然是为了减少请求啦,通过多个js或css合并成一个文件,多张小图片拼合成Sprite图,可以让多个HTTP请求减少为一个,减少额外的协议开销,而提升性能。”如是道也 “当然,一个HTTP的请求的body太大也是不合理的,有个度。文件的合并也会牺牲模块化和缓存粒度,可以把“稳定”的代码or 小图 合并为一个文件or一张Sprite,让其充分地缓存起来,从而区分开迭代快的文件” 我不明白晨伯的问题,就稍微补充了一下方案。

晨伯起来又,略疼,略疼。话说多年的程序员交流都用这种肢体动作了吗?

所有的HTTP2.0的请求都在一个TCP链接上

HTTP2.0所有通信都是在一个TCP连接上完成。HTTP 2.0 把 HTTP 协议通信的基本单位缩小为一个一个的帧,这些帧对应 着逻辑流中的消息。并行地在同一个 TCP 连接上双向交换消息。就好比,我请求一个页面http://www.qq.com。页面上所有的资源请求都是客户端与服务器上的一条TCP上请求和响应的! 有关注TCP性能的同学就会知道,HTTP性能的关键在于低延迟而不是高带宽!大多数HTTP 连接的时间都很短,而且是突发性的,但TCP 只在长时间连接传输大块数据时效率才最高。HTTP 2.0 通过让所有数据流共用同一个连接,可以更有效地使用TCP 连接,让高带宽也能真正的服务于HTTP的性能提升。

同时,单链接多资源的方式,使到至上而下的层面都得到了好处:

  1. 可以减少服务链接压力,内存占用少了,连接吞吐量大了
  2. 由于 TCP 连接减少而使网络拥塞状况得以改观;
  3. 慢启动时间减少,拥塞和丢包恢复速度更快。

也就是说,“资源合并减少请求”的优化手段对于HTTP2.0来说是没有效果的,只会增大无用的工作量而已。

他说得好有道理,我竟然掩脸而对(因为脸被打疼了)。 “你在再我说说,这些cdn1.cn,cdn2.cn,cdn3.cn是什么回事啊”晨伯又问到。 “因为HTTP1.x上如果一个只用一个持久链接,请求只能一个一个顺序请求,为了高效地并行下载资源,浏览器允许我们打开多个TCP会话,但是一个域名下限制6个链接。为了突破这些限制,我们可以域名分区,提高并行下载资源能力…..”我只好把我当年知道的说出来 当时我就有预感要,而晨伯总是按套路出牌….

并行双向字节流的请求和响应

在HTTP2.0上,客户端和服务器可以把HTTP 消息分解为互不依赖的帧,然后乱序发送,最后再在另一端把它们重新组合起来。注意,同一链接上有多个不同方向的数据流在传输。客户端可以一边乱序发送stream,也可以一边接收者服务器的响应,而服务器那端同理。

把 HTTP 消息分解为独立的帧,交错发送,然后在另一端重新组装是 HTTP 2.0 最 重要的一项增强。事实上,这个机制会在整个 Web 技术栈中引发一系列连锁反应, 从而带来巨大的性能提升,因为:

可以并行交错地发送请求,请求之间互不影响; 可以并行交错地发送响应,响应之间互不干扰; 只使用一个连接即可并行发送多个请求和响应; 消除不必要的延迟,从而减少页面加载的时间;

那么也就是说“域名分区”这种优化手段对于HTTP2.0是无用的,因为资源都是并行交错发送,且没有限制,不需要额外的多域名并行下载。

“既然所有资源都是并行交错发送,会不会出现这样的情况【浏览器明明在等关键的 CSS 和JS,你TMD的服务器还在发送图片】” 我疑问道。 晨伯又。我开始确信,这是多年后程序员的肢体礼仪方式。

HTTP2.0的请求优先级

每个HTTP2.0流里面有个优先值,这个优先值确定着客户端和服务器处理不同的流采取不同的优先级策略,高优先级的流都应该优先发送,但又不会绝对的。绝对地准守,可能又会引入首队阻塞的问题:高优先级的请求慢导致阻塞其他资源交付。分配处理资源和客户端与服务器间的带宽,不同优先级的混合也是必须的。

“有了优先级,HTTP2.0根本不会发生【浏览器明明在等关键的 CSS 和JS,你TMD的服务器还在发送黄图】”晨伯道。 “我根本没有说是服务器在发黄图,好不好。”我吐槽了一下。 “还有还有,你这里的一段base64内嵌图片又是什么回事?是黄图吗?” 晨伯又挑战我了。 内嵌图片这种,有使用条件的优化手段,我还是不要说话好,不然的话按照这个故事的尿性,他应该又要飞拳我。

HTTP2.0的服务器推送 HTTP 2.0 新增的一个强大的新功能,就是服务器可以对一个客户端请求发送多个响应。换句话说,服务器可以强奸你的浏览器,哦不,应该是,除了对最初请求的响应外,服务器还可以额外向客户端推送资源,而无需客户端明确地请求。 当浏览器请求一个html,服务器其实大概知道你是接下来要请求资源了,而不需要等待浏览器得到html后解析页面再发送资源请求。我们常用的内嵌图片也可以理解为一种强制的服务器推送:我请求html,却内嵌了张黄图。

有了HTTP2.0的服务器推送,HTTP1.x时代的内嵌资源的优化手段也变得没有意义了。而且使用服务器推送的资源的方式更加高效,因为客户端还可以缓存起来,甚至可以由不同的页面共享(依旧遵循同源策略)。当然,你是个正直的浏览器,是可以决绝服务器推送的黄图的。

不知道为什么,说到黄图这个家伙就兴奋起来了,再也没有打我了。然后交谈就变成了16+周岁的少女不宜收听的内容了。不过HTTP2.0的知识收获了不少。

到了我要面试的日子了,互联网公司A果真要(笔试|鄙视)一下我。我写出了下面的页面

在场面试官,纷纷鼓掌站了起来,“如此高效的页面,难得啊~你被录取了!”。 这看着这份如同我前端实习时候写的页面,我心中默默感叹“十年前端,终归如初”。 出于礼貌,我想起了晨伯教我的新式前端工程师肢体礼仪,然后…..

参考: http://chimera.labs.oreilly.com/books/1230000000545/ch12.html#_sending_application_data https://thecustomizewindows.com/2014/08/http-2-0-changes-expected-new-standard-2/