Open bibi7 opened 5 years ago
想了想讲一个http2的多路复用其实要先回顾一下http1的请求方式
假如小哔打开百度并且输入“什么是多路复用”,直到刷新出了新页面,那么大概率是有如下几个步骤:
这部分更完整的中间过程专门拿出来单独写一篇好了,反正简单点就是如上几个步骤。
更细分一下,Http1与Http1.x还有点其他的差别。
一个正常的html页面肯定不止一个资源,往往伴随着几十个资源的请求,Http1坑在每一个资源的请求完毕后,TCP都会断开,也就是重新发起另一个资源请求的时候又要进行一次三次握手。 偷一张图:
Http1.1增加了一个Connection字段,通过设置Keep-Alive可以保持HTTP连接不断开,避免了每次客户端与服务器请求都要重复建立释放建立TCP连接不每次关闭TCP,听起来好像是解决了问题。 题外话,cache-control等缓存处理也是1.1加入的。
再偷一张图:
不过还是有几个问题:
在http1中,所有的资源请求都是单独的tcp,所以理论上不会阻塞。 但是http1.1中默认开启了keep-alive,不用重复创建TCP,且引入了管道机制(pipelining),即在同一个TCP连接里面,客户端可以同时发送多个请求,同一个tcp连接可能存在着好几个资源请求,且是按照次序进行的。因为串行返回响应机制的原因,下一个资源的响应强制依赖着上一个资源的响应结束,要是响应时间特别慢,就会引起队头阻塞(Head-of-line blocking) 换句话来说,只有等到a响应的资源完全传输完毕后,b响应的资源才能开始传输。也就是说,不允许同时存在两个并行的响应。
keep-alive
http1.x可支持多条TCP链接,但是最大值为6条。但依旧无法达到完美的六倍速
http2主要带来了以下几点东西:
再偷两张图:
在新引进的二进制分帧层上,HTTP/2 将所有传输的信息分割为更小的消息和帧,且都采用二进制格式的编码。HTTP/2 规范规定了10种不同的帧。 如图所示,新的传输方式主要分为HEADERS帧和DATA帧。在新的传输方式中,http2把请求分割成了多部分,然后通过发起一个流对这些帧进行发送,最后在另一端将同一个流的帧重新组合。
HEADERS帧
DATA帧
基于刚才提到的二进制分层的概念,http2在发送消息的时候会对请求进行拆分,拆出来的帧都会带上一个Stream ID,这样在另一端接收这些帧后就可以根据编号对它们进行组合。即:所有的HTTP2.0通信都在一个TCP连接上完成,这个连接可以承载任意数量的双向数据流。
Stream ID
HTTP/2 中,流可以有一个优先级属性(即“权重”)
h2在一个tcp连接创建多个流。每个流可以有从属关系,比如说根据浏览器加载的优先级顺序(主请求>CSS>能改变DOM结构的JS文件>图片和字体资源文件)建立一条依赖关系链。处于同一等级的依赖关系中可以设置权重。权重用于分配传输信道资源多少。
上百个请求中,往往百分之90的请求头都是相似的,同时请求头又对一次请求的整体大小中占了大头,那么如何进行这些首部压缩? h2会维护一份请求头表,表中用索引代表首部名,或者首部键 - 值对。 针对这些绝大部分都是一样的请求头,h2做了类似如下处理:
HTTP/2 规范规定了10种不同的帧,其中有一种名为“PUSH_PROMISE”,就是在服务器推送的时候发送的。当客户端解析帧时,发现它是一个 PUSH_PROMISE 类型,便会准备接收服务端要推送的流。
当服务器响应了 HTML 请求后,可以知道客户端接下来要发送 JS 请求、CSS 请求,于是服务器通过推送的方式(主动发起新流,而不是等客户端请求然后再响应),向客户端发出要约(PUSH_PROMISE)。当然,客户端可以选择缓存这个资源,也可以拒绝这个资源。
相关: HTTP1.0 HTTP1.1 HTTP2.0 主要特性对比
想了想讲一个http2的多路复用其实要先回顾一下http1的请求方式
Http1/Http1.1中的资源请求
假如小哔打开百度并且输入“什么是多路复用”,直到刷新出了新页面,那么大概率是有如下几个步骤:
这部分更完整的中间过程专门拿出来单独写一篇好了,反正简单点就是如上几个步骤。
更细分一下,Http1与Http1.x还有点其他的差别。
Http1
一个正常的html页面肯定不止一个资源,往往伴随着几十个资源的请求,Http1坑在每一个资源的请求完毕后,TCP都会断开,也就是重新发起另一个资源请求的时候又要进行一次三次握手。 偷一张图:
Http1.1
Http1.1增加了一个Connection字段,通过设置Keep-Alive可以保持HTTP连接不断开,避免了每次客户端与服务器请求都要重复建立释放建立TCP连接不每次关闭TCP,听起来好像是解决了问题。 题外话,cache-control等缓存处理也是1.1加入的。
再偷一张图:
不过还是有几个问题:
在http1中,所有的资源请求都是单独的tcp,所以理论上不会阻塞。 但是http1.1中默认开启了
keep-alive
,不用重复创建TCP,且引入了管道机制(pipelining),即在同一个TCP连接里面,客户端可以同时发送多个请求,同一个tcp连接可能存在着好几个资源请求,且是按照次序进行的。因为串行返回响应机制的原因,下一个资源的响应强制依赖着上一个资源的响应结束,要是响应时间特别慢,就会引起队头阻塞(Head-of-line blocking) 换句话来说,只有等到a响应的资源完全传输完毕后,b响应的资源才能开始传输。也就是说,不允许同时存在两个并行的响应。http1.x可支持多条TCP链接,但是最大值为6条。但依旧无法达到完美的六倍速
Http2
http2主要带来了以下几点东西:
二进制分层(Binary Framing Layer)
再偷两张图:
在新引进的二进制分帧层上,HTTP/2 将所有传输的信息分割为更小的消息和帧,且都采用二进制格式的编码。HTTP/2 规范规定了10种不同的帧。 如图所示,新的传输方式主要分为
HEADERS帧
和DATA帧
。在新的传输方式中,http2把请求分割成了多部分,然后通过发起一个流对这些帧进行发送,最后在另一端将同一个流的帧重新组合。多向请求与响应(多路复用)
基于刚才提到的二进制分层的概念,http2在发送消息的时候会对请求进行拆分,拆出来的帧都会带上一个
Stream ID
,这样在另一端接收这些帧后就可以根据编号对它们进行组合。即:所有的HTTP2.0通信都在一个TCP连接上完成,这个连接可以承载任意数量的双向数据流。优先级和依赖性
HTTP/2 中,流可以有一个优先级属性(即“权重”)
首部压缩
上百个请求中,往往百分之90的请求头都是相似的,同时请求头又对一次请求的整体大小中占了大头,那么如何进行这些首部压缩? h2会维护一份请求头表,表中用索引代表首部名,或者首部键 - 值对。 针对这些绝大部分都是一样的请求头,h2做了类似如下处理:
服务器推送(server Push)
HTTP/2 规范规定了10种不同的帧,其中有一种名为“PUSH_PROMISE”,就是在服务器推送的时候发送的。当客户端解析帧时,发现它是一个 PUSH_PROMISE 类型,便会准备接收服务端要推送的流。
当服务器响应了 HTML 请求后,可以知道客户端接下来要发送 JS 请求、CSS 请求,于是服务器通过推送的方式(主动发起新流,而不是等客户端请求然后再响应),向客户端发出要约(PUSH_PROMISE)。当然,客户端可以选择缓存这个资源,也可以拒绝这个资源。