HTTP/2
更新的内容是:
优先级
头部压缩
完整内容,点查看原文。
优先级,Prioritization
浏览器在渲染应用页面时需要加载很多资源,这些资源本身就有重要程度的差异,优先加载重要资源有利于浏览器更高效快速地渲染必要的部分,尽快展示给用户,提升用户体验。HTTP/2 采用多路复用技术,同一源(服务器)的全部资源使用一个连接完成发送,为了避免线头堵塞,这时候资源传输的顺序就尤为重要!
线头堵塞,HOB,Head Of Line Blocking,队列前面的 packet 由于某些原因被延迟,进而会导致后面的 packets 被 blocked 的现象。就像前面出现交通状况了,后边会堵车。
HTTP/2 允许我们在获取资源时,指定资源的权重,进而通知服务器,那些资源应该优先传输。通常我们什么都不需要做,浏览器和 HTTP/2 服务器已经帮我们处理好了具体的细节。
影响优先级的指标主要是:权重(weight)和依赖关系(parent)。
浏览器在请求时,通常会依赖资源类型给出权重,在请求的 HEADERS 帧和 PRIORITY 帧中传输到服务器端。通常来说,html 请求权重最高,css、images、js、fonts 相对低一些,通常是静态分配的。而依赖关系由资源的 Referer 来确定。
服务器在获取到资源的优先相关信息时,会据此构建优先级树,来指导服务器的资源分配,包括 CPU、Memory、带宽等。优先级树,会依赖资源的依赖关系,资源权重,parent 资源权重等来确定。
传输数据时,先根据依赖关系层级选择,当依赖层级相同时,再根据计算出来的相对权重选择。
// **相对权重**大概的计算方式如下:
相对权重 = 资源权重 * 上级资源相对权重复制
在多路复用上,有了资源的传输权重,岂不是如虎添翼!
头部压缩,Header Compression
HTTP 请求时,头部往往会出现大量的重复信息。例如若有大量的 cookie,每次浏览器向服务器请求时,都会携带大量的且内容相同的 cookie,是不是造成了带宽传输的浪费?再比如 UserAgent,很长一段代理信息,但是从开始到结束,这个值是不变的,没有必要反复的传输。
HTTP/2 头压缩算法为 HPACK,思路是将请求和响应头中特定的关键字给编上索引号码,这样在传输固定内容时,仅仅需要传输索引号码即可,因为 B/S 两端都可以利用该这个索引号码来确定头内容是什么。
例如:静态表
Index | Header Name | Header Value |
---|---|---|
2 | :method | GET |
3 | :method | POST |
…… | …… | …… |
8 | :status | 200 |
13 | :status | 404 |
33 | date | |
58 | user-agent | 可变的 user-agent 值 |
…. |
存储非预定义头(例如 x-powered-by
)时,会使用另一张结构类似的表, 称为动态表。也会将每对头 Name:Value 做成索引。
例如,动态表:
Index | Header Name | Header Value |
---|---|---|
68 | x-powered-by | some value |
…… | …… | …… |
两个表结合,HPACK 就得到了全部使用的头 Name:Value 的索引集合。这个索引集合,B、S 两端同时维护,内容保持一致。这样,B/S 在传输时,仅仅需要传输索引号和变化的值即可,不再需要传递大量的重复数据了。
除此之外,传输数据时,头部还会采用静态霍夫曼编码来压缩数据,减少体积。
看一张图:来自 https://www.oreilly.com/
上图中,演示了一个请求头,基于静态表,形成编码后的请求头实体的过程,其中:
2,7,62,就是静态表的索引,只需要传递索引号即可,B、S 两端都知道内容是什么
19,value 是新的,name 是索引19对应的,value 采用了 huffman 编码
最后还有一组自定义的 name:value 对,都采用了 huffman 编码
再看一图:来自 https://www.oreilly.com/
上图中,请求 #2, 所需要发送的头仅有一条即可,因为其他的头未发生改动,只需要将改动发送即可!
原文查看全部
未完待续...