The standardization effort was supported by Chrome, Opera, Firefox,[9] Internet Explorer 11, Safari, Amazon Silk, and Edge browsers.[10] Most major browsers had added HTTP/2 support by the end of 2015.[11] According to W3Techs, as of November 2017, 20.5% of the top 10 million websites supported HTTP/2.
这是一段来自维基百科的关于HTTP2的说明,截止2015年底,主流浏览器都已经对HTTP2做了支持,根据2017年11月的W3Techs报告说明,全球有1/5的大型网站都已经使用了HTTP2了。作为码农的你已经可以预料HTTP2的时代即将到来,对于HTTP2的技术细节你都准备好了么?
HTTP2的设计要点
Header压缩
Server Push
Pipelining & Mulplexing
我们平常听到的GZIP压缩仅仅是针对HTTP请求的Body部分进行的,这只能算是半压缩。对于很多API服务来说,返回的内容体其实并不大,这个时候请求头就占据了大部分流量。HTTP2将魔爪伸到了HTTP头部,这回是彻底的对整个请求都进行压缩了。
HTTP2的头压缩原理完全不同于HTTP1.1,它将常用的HEADER键值对映射到一个静态表里面的索引值,于是很多头部的键值对使用一个位置索引来表示就可以了。这样便大大节省了头部消息的长度。对于那些不常用的自定义的头部会使用一个动态表来维护,具体原理有一定复杂度,这里就不再啰嗦了。
Server Push不同于Websocket,Server Push一般是指服务器主动向客户端推送数据,这是一种单向的主动推送,而WebSocket是双向的,这两种技术不是竞争关系。Server Push可以用在服务器主动向客户端推送静态资源,比如浏览器请求index.html时,服务器除了返回网页内容外,还会将index.html页面里面的各种css和js一起推送到浏览器缓存起来,当浏览器分析了网页内容发现静态资源时,不需要再去服务器请求一次,它只需要从缓存里直接拿就可以了。不过现代的网站的静态资源大多都是CDN架构的,静态资源都在第三方服务器,Server Push在这方面作用并不大。Server Push还可以用在推送通知消息,比如谁关注了你,谁给你点了赞等,这个可以替代古老的Comet技术和近几年Google推广的SPDY协议,它需要服务器维持当前的TCP通道不关闭,需要持续占用服务器资源。
Pipeline是指后一个HTTP请求无需等待前一个HTTP请求返回结果就可以提前发起。HTTP1.1也有Pipeline支持,但是有所不足,并行的还不够彻底。它可以提前发起请求,但是却限定了返回结果必须和收到请求的顺序保持一致而不能乱序。如果第一个请求服务器处理慢了,那么后续的返回结果客户端无法立即收到,而必须等到第一个结果全部返回了才行。HTTP2则解决了这个问题,它支持乱序返回,甚至不同请求的返回结果的分块【HTTP Chunk】也可以交叉返回而不会混乱,这种技术称之为Multiplexing【多路复用】。
HTTP2底层协议
HTTP2协议是二进制协议,不同于HTTP1.1的文本协议。文本协议是以特殊的符号结尾【换行回车符】来分割消息的,而二进制协议是通过字节长度来分割消息。二进制协议虽然直观性不如文本协议,但是在实现的时候要简单直接一些。
HTTP2为支持多路复用,在同一条TCP通道上支持发送多个资源/请求,将每条资源/请求定义为一个Stream【流】,同一个TCP通道可以传输多个Stream。同时为了支持多个资源的并行交错发送,将Stream再次分割为多个Frame【帧】,帧与帧之间可以交错发送。接收端通过流ID将这些帧组装起来,通一个流ID的帧属于同一个资源/请求。因为TCP协议已经可以保证消息包是有序的,所以接收端不必担心乱序问题。
HTTP2的帧格式非常简单,就是长度+类型+标志位+流ID+PayLoad,长度就是PayLoad的字节数,类型为一个字节,标志位为1个字节,流ID为4个字节,剩下的长度就是PayLoad。不同类型的帧PayLoad不一样,标志位也不一样。
HTTP2标准里定义了10种类型的帧。
HEADERS帧 头信息,对应于HTTP HEADER
DATA帧 对应于HTTP Response Body
PRIORITY帧 用于调整流的优先级
RST_STREAM帧 流终止帧,用于中断资源的传输
SETTINGS帧 用户客户服务器交流连接配置信息
PUSH_PROMISE帧 服务器向客户端主动推送资源
GOAWAY帧 通知对方断开连接
PING帧 心跳帧,检测往返时间和连接可用性
WINDOW_UPDATE帧 调整帧大小
CONTINUATION帧 HEADERS太大时的续帧
HTTP2标准定义了3个标志位
END_STREAM 流结束标志,表示当前帧是流的最后一个帧
END_HEADERS 头结束表示,表示当前帧是头信息的最后一个帧
PADDED 填充标志,在数据Payload里填充无用信息,用于干扰信道监听
对于一个普通的GET请求来说,它使用一个HEADERS帧就可以表达。HEADERS帧会设置标志位END_STREAM和END_HEADERS表示当前帧是一个完整的HEADERS帧,也是一个完整的HTTP请求流。
对于一个普通的GET请求响应来说,它使用一个HEADERS帧和多个DATA帧就可以表达。HEADERS帧设置END_HEADERS表示当前帧是一个完整的HEADERS帧,后面的DATA帧表示返回的数据,对应Response Body。在HTTP1.1里面返回的Body长度较大,就需要分Chunk进行传输。HTTP2是通过分成多个DATA帧来进行的,最后一个DATA帧有一个END_STREAM标记表示Body的结束。
如果HEADERS太大无法用一个HEADERS帧表达,可以后面跟多个CONTINUATION帧,最后一个帧附加END_HEADERS标志即可。
在服务器主动向客户端推送资源时,同一个资源流里不使用HEADERS帧,取而代之的是PUSH_PROMISE帧,表示服务器承诺客户端即将推送指定资源数据,用于区别一个常规的HTTP GET资源请求。
如果一个TCP连接正在被用于客户端从服务器下载一个大型文件,那么客户端取消发送这个文件的办法只有一个,就是关闭连接。HTTP2则可以在不关闭连接的情况下终止发送文件,客户端向服务器发送一个RST_STREAM帧通知服务器停止相应的资源流即可。这个连接还可以继续服务其它的请求。
HTTP2服务器接收到一个客户端的连接时,第一个要干的事就是和客户端交换SETTINGS帧信息,告知对方一些交互元信息的设置,例如是否开启服务器推送,并行的最大流数量,单帧最大长度等。
在客户端观看视频流时,如果服务器发送的太慢会影响观看体验,如果发的太快,会对客户端的浏览器缓存造成压力。客户端可以使用WINDOW_UPDATE帧通知服务器调整帧窗口大小进而控制服务区发送的数据速率。
阅读相关文章,关注微信公众号/知乎专栏/头条号【码洞】
网友评论