bibi7 / fe-daily-increase

一个记录开发日常和奇奇怪怪的点的repo
MIT License
5 stars 0 forks source link

http2多路复用 #34

Open bibi7 opened 5 years ago

bibi7 commented 5 years ago

想了想讲一个http2的多路复用其实要先回顾一下http1的请求方式

Http1/Http1.1中的资源请求

假如小哔打开百度并且输入“什么是多路复用”,直到刷新出了新页面,那么大概率是有如下几个步骤:

  1. dns查询
  2. dns返回服务器ip,小哔的电脑和服务器开始三次握手
  3. 三次握手完毕,小哔的电脑开始发起一次http request
  4. 服务器收到request,响应一次response
  5. 小哔的电脑拿到response

这部分更完整的中间过程专门拿出来单独写一篇好了,反正简单点就是如上几个步骤。

更细分一下,Http1与Http1.x还有点其他的差别。

Http1

一个正常的html页面肯定不止一个资源,往往伴随着几十个资源的请求,Http1坑在每一个资源的请求完毕后,TCP都会断开,也就是重新发起另一个资源请求的时候又要进行一次三次握手。 偷一张图: image

Http1.1

Http1.1增加了一个Connection字段,通过设置Keep-Alive可以保持HTTP连接不断开,避免了每次客户端与服务器请求都要重复建立释放建立TCP连接不每次关闭TCP,听起来好像是解决了问题。 题外话,cache-control等缓存处理也是1.1加入的。

再偷一张图: image

不过还是有几个问题:

  1. 在http1中,所有的资源请求都是单独的tcp,所以理论上不会阻塞。 但是http1.1中默认开启了keep-alive,不用重复创建TCP,且引入了管道机制(pipelining),即在同一个TCP连接里面,客户端可以同时发送多个请求,同一个tcp连接可能存在着好几个资源请求,且是按照次序进行的。因为串行返回响应机制的原因,下一个资源的响应强制依赖着上一个资源的响应结束,要是响应时间特别慢,就会引起队头阻塞(Head-of-line blocking) 换句话来说,只有等到a响应的资源完全传输完毕后,b响应的资源才能开始传输。也就是说,不允许同时存在两个并行的响应。

  2. http1.x可支持多条TCP链接,但是最大值为6条。但依旧无法达到完美的六倍速

Http2

http2主要带来了以下几点东西:

  1. 二进制分层
  2. 多向请求与响应(多路复用)
  3. 优先级和依赖性
  4. 首部压缩
  5. 服务器推送(server Push)

二进制分层(Binary Framing Layer)

再偷两张图: image

image

在新引进的二进制分帧层上,HTTP/2 将所有传输的信息分割为更小的消息和帧,且都采用二进制格式的编码。HTTP/2 规范规定了10种不同的帧。 如图所示,新的传输方式主要分为HEADERS帧DATA帧。在新的传输方式中,http2把请求分割成了多部分,然后通过发起一个流对这些帧进行发送,最后在另一端将同一个流的帧重新组合。

多向请求与响应(多路复用)

基于刚才提到的二进制分层的概念,http2在发送消息的时候会对请求进行拆分,拆出来的帧都会带上一个Stream ID,这样在另一端接收这些帧后就可以根据编号对它们进行组合。即:所有的HTTP2.0通信都在一个TCP连接上完成,这个连接可以承载任意数量的双向数据流。

优先级和依赖性

HTTP/2 中,流可以有一个优先级属性(即“权重”)

  1. 可以在 HEADERS 帧中包含优先级 priority 属性;
  2. 可以单独通过 PRIORITY 帧专门设置流的优先级属性。

h2在一个tcp连接创建多个流。每个流可以有从属关系,比如说根据浏览器加载的优先级顺序(主请求>CSS>能改变DOM结构的JS文件>图片和字体资源文件)建立一条依赖关系链。处于同一等级的依赖关系中可以设置权重。权重用于分配传输信道资源多少。

首部压缩

上百个请求中,往往百分之90的请求头都是相似的,同时请求头又对一次请求的整体大小中占了大头,那么如何进行这些首部压缩? image h2会维护一份请求头表,表中用索引代表首部名,或者首部键 - 值对。 针对这些绝大部分都是一样的请求头,h2做了类似如下处理:

  1. 第一次请求中,请求头中的信息不在维护的首部表里面,那么就录入相关头部信息
  2. 第二次请求,发现该请求头的信息已经存在于表中,那么不需要再次发送
  3. 第三次请求,若查找发现部分首部信息不在索引表中,则发送该部分信首部息即可

服务器推送(server Push)

HTTP/2 规范规定了10种不同的帧,其中有一种名为“PUSH_PROMISE”,就是在服务器推送的时候发送的。当客户端解析帧时,发现它是一个 PUSH_PROMISE 类型,便会准备接收服务端要推送的流。

当服务器响应了 HTML 请求后,可以知道客户端接下来要发送 JS 请求、CSS 请求,于是服务器通过推送的方式(主动发起新流,而不是等客户端请求然后再响应),向客户端发出要约(PUSH_PROMISE)。当然,客户端可以选择缓存这个资源,也可以拒绝这个资源。

bibi7 commented 4 years ago
  1. 从get和post两种请求方式,引申到一些其他的请求方式。
  2. 进而引申出http是什么?
  3. 进一步深入下去,http1和1.1?http2?
  4. 是否了解过https?
  5. https和http有什么不同?https是如何加密的?
bibi7 commented 4 years ago

相关: HTTP1.0 HTTP1.1 HTTP2.0 主要特性对比