《HTTP/2 基础教程》 阅读摘要

最近粗线了很多 HTTP2 相关的帖子和讨论,感受新一轮的潮流在造成,因此最近找了本 HTTP2 相关书籍作知识储备,恰好记成笔记以备后询 ~css

这本书自己不错,缺点就是翻译的有点蹩脚,另外由于是 2017 年出的书,因此有些内容时效性不太好,好比关于 Chrome 的部分,因此我根据 Chrome 的官方文档增长了点内容 😅html

若是但愿获取本书的 PDF 资源,能够关注文末二维码加微信群找群主要~前端

1. HTTP进化史

1.1 HTTP/0.九、HTTP/1.0、HTTP/1.1

  1. HTTP/0.9: 是个至关简单的协议。它只有一个方法(GET),没有首部,其设计目标也无非是获取 HTML(也就是说没有图片,只有文本)。
  2. HTTP/1.0: 多了不少功能,首部、错误码、重定向、条件请求等,但仍存在不少瑕疵,尤为是不能让多个请求共用一个链接、缺乏强制的 Host 首部、缓存的选择也至关简陋,这三点影响了 Web 可扩展的方式。
  3. HTTP/1.1: 增长了缓存相关首部的扩展、OPTIONS 方法、Upgrade 首部、Range 请求、压缩和传输编码、管道化等功能。由于强制要求客户端提供 Host 首部,因此虚拟主机托管成为可能,也就是在一个 IP 上提供多个 Web 服务。另外使用了 keep-alive 以后,Web 服务器也不须要在每一个响应以后关闭链接。这对于提高性能和效率而言意义重大,由于浏览器不再用为每一个请求从新发起 TCP 链接了。

1.2 HTTP/2

HTTP2 被但愿达到如下特性:web

  • 相比 HTTP/1.1,性能显著提升;
  • 解决 HTTP 中的队头阻塞问题;
  • 并行的实现机制不依赖与服务器创建多个链接,从而提高 TCP 链接的利用率,特别是在拥塞控制方面;
  • 保留 HTTP/1.1 的语义,能够利用已有的文档资源,包括(但不限于) HTTP 方法、状态码、URI 和首部字段;
  • 明肯定义 HTTP/2.0 和 HTTP/1.x 交互的方法,特别是经过中介时的方法(双向);
  • 明确指出它们能够被合理使用的新的扩展点和策略。

2. HTTP/2 快速入门

2.1 启动并运行

不少网站已经在用HTTP/2(h2)了,好比 Facebook、Instagram、Twitter 等,下面介绍如下如何本身搭建 h2 服务器。要运行 h2 服务器,主要分两步:ajax

  1. 获取并安装一个支持 h2 的 Web 服务器
  2. 下载并安装一张 TLS 证书,让浏览器和服务器经过 h2 链接

2.2 获取证书

证书能够经过三种方式获取:算法

  1. 使用在线资源
  2. 本身建立一张证书
  3. 从数字证书认证机构(CA)申请一张证书

前两个方法 将建立自签名证书,仅用于测试,因为不是 CA 签发的,浏览器会报警chrome

后面关于建立 h2 服务器的步骤就不记了,能够百度下api

3. Web优化『黑魔法』的动机与方式

3.1 当前的性能挑战

3.1.1 剖析Web页面请求

从用户在浏览器中点击连接到页面呈如今屏幕上,在此期间到底发生了什么?浏览器请求 Web 页面时,会执行重复流程,获取在屏幕上绘制页面须要的全部信息。为了更容易理解,咱们把这一过程分红两部分:资源获取、页面解析/渲染。promise

资源请求流程图:浏览器

流程为:

  1. 把待请求 URL 放入队列
  2. 解析 URL 中域名的 IP 地址(A)
  3. 创建与目标主机的 TCP 链接(B)
  4. 若是是 HTTPS 请求,初始化并完成 TLS 握手(C)
  5. 向页面对应的 URL 发送请求。

资源响应流程图:

  1. 接收响应
  2. 若是(接收的)是主体 HTML,那么解析它,并针对页面中的资源触发优先获取机制(A)
  3. 若是页面上的关键资源已经接收到,就开始渲染页面(B)
  4. 接收其余资源,继续解析渲染,直到结束(C)

页面上的每一次点击,都须要重复执行前面那些流程,给网络带宽和设备资源带来压力。Web 性能优化的的核心,就是加快甚至干脆去掉其中的某些步骤。

3.1.2 关键性能指标

下面网络级别的性能指标,它会影响整个 Web 页面加载。

  1. 延迟: 指 IP 数据包从一个网络端点到另外一个网络端点所花费的时间。
  2. 带宽: 只要带宽没有饱和,两个网络端点之间的链接会一次处理尽量多的数据量。
  3. DNS查询: 在客户端可以获取 Web 页面前,它须要经过域名系统(DNS)把主机名称转换成 IP 地址。
  4. 创建链接时间: 在客户端和服务器之间创建链接须要三次握手。握手时间通常与客户端和服务器之间的延迟有关。
  5. TLS协商时间: 若是客户端发起 HTTPS 链接,它还须要进行传输层安全协议(TLS)协商,TLS 会形成额外的往返传输。
  6. 首字节时间(TTFB): TTFB 是指客户端从开始定位到 Web 页面,至接收到主体页面响应的第一字节所耗费的时间。它包含了以前提到的各类耗时,还要加上服务器处理时间。对于主体页面上的资源,TTFB 测量的是从浏览器发起请求至收到其第一字节之间的耗时。
  7. 内容下载时间: 等同于被请求资源的最后字节到达时间(TTLB)。
  8. 开始渲染时间: 客户端的屏幕上何时开始显示内容?这个指标测量的是用户看到空白页面的时长。
  9. 文档加载完成时间: 这是客户端浏览器认为页面加载完毕的时间。

3.1.3 HTTP/1 的问题

HTTP/1 的问题天然是 HTTP/2 要解决的核心问题

1. 队头阻塞

浏览器不多只从一个域名获取一份资源,通常但愿能同时获取许多资源。h1 有个特性叫管道化(pipelining),容许一次发送一组请求,可是只能按照发送顺序依次接收响应。管道化备受互操做性和部署的各类问题的困扰,基本没有实用价值。
在请求应答过程当中,若是出现任何情况,剩下全部的工做都会被阻塞在那次请求应答以后。这就是『队头阻塞』,它会阻碍网络传输和 Web 页面渲染,直至失去响应。为了防止这种问题,现代浏览器会针对单个域名开启 6 个链接,经过各个链接分别发送请求。它实现了某种程度上的并行,可是每一个链接仍会受到的影响。

2. 低效的 TCP 利用

传输控制协议(TCP)的设计思路是:对假设状况很保守,并可以公平对待同一网络的不一样流量的应用。涉及的核心概念就是拥塞窗口(congestion window)。『拥塞窗口』是指,在接收方确认数据包以前,发送方能够发出的 TCP 包的数量。 例如,若是拥塞窗口指定为 1,那么发送方发出 1 个数据包以后,只有接收方确认了那个包,才能发送下一个。

TCP 有个概念叫慢启动(Slow Start),它用来探索当前链接对应拥塞窗口的合适大小。慢启动的设计目标是为了让新链接搞清楚当前网络情况,避免给已经拥堵的网络继续添乱。它容许发送者在收到每一个确认回复后额外发送 1 个未确认包。这意味着新链接在收到 1 个确认回复以后,能够发送 2 个数据包;在收到 2 个确认回复以后,能够发 4 个,以此类推。这种几何级数增加很快到达协议规定的发包数上限,这时候链接将进入拥塞避免阶段。

TCP拥塞控制

这种机制须要几回往返数据请求才能得知最佳拥塞窗口大小。但在解决性能问题时,就这区区几回数据往返也是很是宝贵的时间成本。若是你把一个数据包设置为最大值下限 1460 字节,那么只能先发送 5840 字节(假定拥塞窗口为 4),而后就须要等待接收确认回复。理想状况下,这须要大约 9 次往返请求来传输完整个页面。除此以外,浏览器通常会针对同一个域名开启 6 个并发链接,每一个链接都免不了拥塞窗口调节。

传统 TCP 实现利用拥塞控制算法会根据数据包的丢失来反馈调整。若是数据包确认丢失了,算法就会缩小拥塞窗口。这就相似于咱们在黑暗的房间摸索,若是腿碰到了桌子就会立刻换个方向。若是遇到超时,也就是等待的回复没有按时抵达,它甚至会完全重置拥塞窗口并从新进入慢启动阶段。新的算法会把其余因素也考虑进来,例如延迟,以提供更妥善的反馈机制。

前面提到过,由于 h1 并不支持多路复用,因此浏览器通常会针对指定域名开启 6 个并发链接。这意味着拥塞窗口波动也会并行发生 6 次。TCP 协议保证那些链接都能正常工做,可是不能保证它们的性能是最优的。

3. 臃肿的消息首部

虽然 h1 提供了压缩被请求内容的机制,可是消息首部却没法压缩。消息首部可不能忽略,尽管它比响应资源小不少,但它可能占据请求的绝大部分(有时候多是所有)。若是算上 cookie,就更大了。

消息首部压缩的缺失也容易致使客户端到达带宽上限,对于低带宽或高拥堵的链路尤为如此。『体育馆效应』(Stadium Effect)就是一个经典例子。若是成千上万人同一时间出如今同一地点(例如重大致育赛事),会迅速耗尽无线蜂窝网络带宽。这时候,若是能压缩请求首部,把请求变得更小,就可以缓解带宽压力,下降系统的总负载。

4. 受限的优先级设置

若是浏览器针对指定域名开启了多个 socket(每一个都会受队头阻塞问题的困扰),开始请求资源,这时候浏览器能指定优先级的方式是有限的:要么发起请求,要么不发起。然而 Web 页面上某些资源会比另外一些更重要,这必然会加剧资源的排队效应。这是由于浏览器为了先请求优先级高的资源,会推迟请求其余资源。可是优先级高的资源获取以后,在处理的过程当中,浏览器并不会发起新的资源请求,因此服务器没法利用这段时间发送优先级低的资源,总的页面下载时间所以延长了。还会出现这样的状况:一个高优先级资源被浏览器发现,可是受制于浏览器处理的方式,它被排在了一个正在获取的低优先级资源以后。

5. 第三方资源

现在 Web 页面上请求的不少资源彻底独立于站点服务器的控制,咱们称这些为第三方资源。现代 Web 页面加载时长中每每有一半消耗在第三方资源上。虽然有不少技巧能把第三方资源对页面性能的影响降到最低,可是不少第三方资源都不在 Web 开发者的控制范围内,因此极可能其中有些资源的性能不好,会延迟甚至阻塞页面渲染。使人扫兴的是, h2 对此也一筹莫展。

3.2 Web性能优化技术

2010 年,谷歌把 Web 性能做为影响页面搜索评分的重要因素之一,性能指标开始在搜索引擎中发挥做用。对于不少 Web 页面,浏览器的大块时间并非用于呈现来自网站的主体内容(一般是 HTML),而是在请求全部资源并渲染页面。

所以,Web 开发者逐渐更多地关注经过减小客户端网络延迟和优化页面渲染性能来提高Web 性能。

3.2.1 Web性能的最佳实践

1. DNS 查询优化

在与服务主机创建链接以前,须要先解析域名;那么,解析越快就越好。下面有一些方法:

  1. 限制不一样域名的数量。固然,这一般不是你能控制的
  2. 保证低限度的解析延迟。了解你的 DNS 服务基础设施的结构,而后从你的最终用户分布的全部地域按期监控解析时间
  3. 在 HTML 或响应中利用 DNS 预取指令。这样,在下载并处理 HTML 的同时,预取指令就能开始解析页面上指定的域名
<link rel="dns-prefetch" href="//ajax.googleapis.com">
2. 优化 TCP 链接

本章前面提到过,开启新链接是一个耗时的过程。若是链接使用 TLS(也确实应该这么作),开销会更高。下降这种开销的方法以下

  1. 尽早终止并响应。借助 CDN,在距离请求用户很近的边缘端点上,请求就能够得到响应,因此能够终止链接,大幅减小创建新链接的通讯延迟。
  2. 实施最新的 TLS 最佳实践来优化 HTTPS。
  3. 利用 preconnect 指令,链接在使用以前就已经创建好了,这样处理流程的关键路径上就没必要考虑链接时间了,preconnect 不光会解析 DNS,还会创建 TCP 握手链接和 TLS 协议(若是须要)
<link rel="preconnect" href="//fonts.example.com" crossorigin>

若是要从同一个域名请求大量资源,浏览器将自动开启到服务器的并发链接,避免资源获取瓶颈。虽然如今大部分浏览器支持 6 个或更多的并发链接数目,但你不能直接控制浏览器针对同一域名的并发链接数。

3. 避免重定向

重定向一般触发与额外域名创建链接。在移动网络中,一次额外的重定向可能把延迟增长数百毫秒,这不利于用户体验,并最终会影响到网站上的业务。简单的解决方案就是完全消灭重定向,由于对于重定向的使每每并无合理缘由。若是它们不能被直接消灭,你还有两个选择:

  1. 利用 CDN 代替客户端在云端实现重定向
  2. 若是是同一域名的重定向,使用 Web 服务器上的 rewrite 规则,避免重定向
4. 客户端缓存

没有什么比直接从本地缓存获取资源来得更快,由于它根本就不须要创建网络链接。

  1. 所谓的纯静态内容,例如图片或带版本的数据,能够在客户端永久缓存。即使 TTL 被设置得很长,好比一个月,它仍是会由于缓存提前回收或清理而过时,这时客户端可能不得不从源头再次获取。
  2. CSS/JS 和个性化资源,缓存时间大约是会话(交互)平均时间的两倍。这段时间足够长,保证大多数用户在浏览网站时可以从本地拉取资源;同时也足够短,几乎能保证下次会话时从网络上拉取最新内容。

能够经过 HTTP 首部指定 cache control 以及键 max-age(以秒为单位),或者 expires 首部。

5. 网络边缘的缓存

我的信息(用户偏好、财务数据等)绝对不能在网络边缘缓存,由于它们不能共享。时间敏感的资源也不该该缓存,例如实时交易系统上的股票报价。这就是说,除此以外其余一切都是能够缓存的,即便仅仅缓存几秒或几分钟。对于那些不是常常更新,然而一旦有变化就必须马上更新的资源,例如重大新闻,能够利用各大 CDN 厂商提供的缓存清理(purging)机制处理。这种模式被称为『一直保留,直到被通知』(Hold til Told),意思是永久缓存这些资源,等收到通知后才删除。

6. 条件缓存

若是缓存 TTL 过时,客户端会向服务器发起请求。在多数状况下,收到的响应其实和缓存的版本是同样的,从新下载已经在缓存里的内容也是一种浪费。HTTP 提供条件请求机制,客户端能以有效方式询问服务器:『若是内容变了,请返回内容自己;不然,直接告诉我内容没变。』当资源不常常变化时,使用条件请求能够显著节省带宽和性能;可是,保证资源的最新版迅速可用也是很是重要的。使用条件缓存能够经过如下方法。

  1. 在请求中包含 HTTP 首部 Last-Modified-Since。仅当最新内容在首部中指定的日期以后被更新过,服务器才返回完整内容;不然只返回 304 响应码,并在响应首部中附带上新的时间戳 Date 字段。
  2. 在请求体中包含实体校验码,或者叫 ETag;它惟一标识所请求的资源。ETag 由服务器 提供,内嵌于资源的响应首部中。服务器会比较当前 ETag 与请求首部中收到的 ETag,若是一致,就只返回 304 响应码;不然返回完整内容。

通常来讲,大多数 Web 服务器会对图片和 CSS/JS 使用这些技术,但你也能够将其用到其余资源。

7. 压缩和代码极简化

全部的文本内容(HTML、JS、CSS、SVG、XML、JSON、字体等),均可以压缩和极简化。这两种方法组合起来,能够显著减小资源大小。更少字节数对应着更少的请求与应答,也就意味着更短的请求时间。

极简化(minification, 混淆)是指从文本资源中剥离全部非核心内容的过程。一般,要考虑方便人类阅读和维护,而浏览器并不关心可读性,放弃代码可读性反而能节省空间。在极简化的基础上,压缩能够进一步减小字节数。它经过可无损还原的算法减小资源大小。在发送资源以前,若是服务器进行压缩处理,能够节省 90% 的大小。

8. 避免阻塞 CSS/JS

在屏幕上绘制第一个像素以前,浏览器必须确保 CSS 已经下载完整。尽管浏览器的预处理器很智能,会尽早请求整个页面所须要的 CSS,可是把 CSS 资源请求放在页面靠前仍然是种最佳实践,具体位置是在文档的 head 标签里,并且要在任何 JS 或图片被请求和处理以前。

默认状况下,若是在 HTML 中定位了 JS,它就会被请求、解析,而后执行。在浏览器处理完这个 JS 以前,会阻止其后任何资源的下载渲染。然而大多数时候,这种默认的阻塞行为致使了没必要要的延迟,甚至会形成单点故障。为了减轻 JS 阻塞带来的潜在影响,下面针对己方资源(你能控制的)和第三方资源(你不能控制的)推荐了不一样的策略

  1. 按期校验这些资源的使用状况。随着时间的变迁,Web 页面可能会持续下载一些再也不须要的 JS,这时最好去掉它。
  2. 若是 JS 执行顺序可有可无,而且必须在 onload 事件触发以前运行,那么能够设置 async 属性,像这样:

    <script async src="/js/myfile.js">

    只需作到下载 JS 与解析 HTML 并行,就能极大地提高总体用户体验。慎用 document.write 指令,由于极可能中断页面执行,因此须要仔细测试。

  3. 若是 JS 执行顺序很重要,而且你也能承受脚本在 DOM 加载完以后运行,那么请使用 defer 属性。像这样

    <script defer src="/js/myjs.js">
  4. 对不会影响到页面初次展现的 JS 脚本,必须在 onload 事件触发以后请求(处理)它。
  5. 若是你不想延迟主页面的 onload 事件,能够考虑经过 iframe 获取 JS,由于它的处理独立于主页面。可是,经过 iframe 下载的 JS 访问不了主页面上的元素。
9. 图片优化

对大多数网站而言,图片的重要性和比重在不断增长。既然图片主导了多数现代网站,优化它们就可以得到最大的性能回报。全部图片优化手段的目标都是在达到指定视觉质量的前提下传输最少的字节。

  1. 图片元信息,例如题材地理位置信息、时间戳、尺寸和像素信息,一般包含在二进制数据里,应该在发送给客户端以前去掉(务必保留版权和色彩描述信息)。这种无损处理可以在图片生成时完成。对于 PNG 图片,通常会节省大概 10% 的空间。
  2. 图片过载(image overloading)是指,图片最终被浏览器自动缩小,要么由于原始尺寸超过了浏览器可视区中的占位大小,要么由于像素超过设备的显示能力。这不只浪费带宽,消耗的 CPU 资源也很可观,这些计算资源有时在手持设备上至关宝贵。想要解决图片过载,能够使用技术手段,针对用户的设备、网络情况和预期的视觉质量,提供裁剪过的图片(就尺寸和质量而言)。

3.2.2 反模式

HTTP/2 对每一个域名只会开启一个链接,因此 HTTP/1.1 下的一些诀窍对它来讲只会拔苗助长。

详细看 6.7 节

3.3 小结

HTTP/1.1 孕育了各类性能优化手段与诀窍,能够帮助咱们深刻理解 Web 及其内部实现。HTTP/2 的目标之一就是淘汰掉众多(并非所有)此类诀窍。

4. HTTP/2 迁移

在升级到 HTTP/2 以前,你应该考虑:

  1. 浏览器对 h2 的支持状况
  2. 迁移到 TLS(HTTPS)的可能性
  3. 对你的网站作基于 h2 的优化(可能对 h1 有副作用)
  4. 网站上的第三方资源
  5. 保持对低版本客户端的兼容

4.1 浏览器的支持状况

任何不支持 h2 的客户端都将简单地退回到 h1,并仍然能够访问你的站点基础设施。

4.2 迁移到 TLS

全部主流浏览器只能访问基于 TLS(即 HTTPS 请求)的 h2。

4.3 撤销针对 HTTP/1.1 的优化

Web 开发者以前花费了大量心血来充分使用 h1,而且已经总结了一些诀窍,例如资源合并、域名拆分、极简化、禁用 cookie 的域名、生成精灵图,等等。因此,当得知这些实践中有些在 h2 下变成反模式时,你可能会感到吃惊。例如,资源合并(把不少 CSS/JS 文件拼合成一个)能避免浏览器发出多个请求。对 h1 而言这很重要,由于发起请求的代价很高;可是在 h2 的世界里,这部分已经作了深度优化。放弃资源合并的结果多是,针对单个资源发起请求的代价很低,但浏览器端能够进行更细粒度的缓存。

详细看 6.7 节

5. HTTP/2 协议

本章将全面探讨 HTTP/2 的底层工做原理,深刻到数据层传输的帧及其通讯方式。

5.1 HTTP/2 分层

HTTP/2 大体能够分为两部分

  1. 分帧层 即 h2 多路复用能力的核心部分,主要目的仍是传输 HTTP
  2. 数据或 http 层 其中包含传统上被认为是 HTTP 及其关联数据的部分,向后兼容 HTTP/1.1

h2 有些特色须要关注一下:

  1. 二进制协议 :h2 的分帧层是基于帧的二进制协议,这方便了机器解析,可是肉眼识别比较困难
  2. 首部压缩 :仅使用二进制协议还不够,h2 的首部还会被深度压缩。这将显著减小传输中的冗余字节
  3. 多路复用 :在调试工具里查看基于 h2 传输的链接的时候,你会发现请求和响应交织在一块儿
  4. 加密传输 :线上传输的绝大部分数据是加密过的,因此在中途读取会更加困难

5.2 链接

与彻底无状态的 h1 不一样的是,h2 把它所承载的帧(frame)和流(stream)共同依赖的链接层元素捆绑在一块儿,其中既包含链接层设置也包含首部表。也就是说,与以前的 HTTP 版本不一样,每一个 h2 链接都有必定的开销。之因此这么设计,是考虑到收益远远超过其开销。

在链接的时候,HTTP/2 提供两种协议发现的机制:

  1. 在链接不加密的状况下,客户端会利用 Upgrade 首部来代表指望使用 h2。若是服务器也能够支持 h2,它会返回一个101 Switching Protocols(协议转换)响应。这增长了一轮完整的请求-响应通讯
  2. 若是链接基于 TLS,状况就不一样了。客户端在 ClientHello 消息中设置 ALPN (Application-Layer Protocol Negotiation,应用层协议协商)扩展来代表指望使用 h2 协议,服务器用一样的方式回复。若是使用这种方式,那么 h2 在建立 TLS 握手的过程当中完成协商,不须要多余的网络通讯。
在协议制定过程当中,很早就把小数点去掉了,这代表将来的 HTTP 版本不能保证语义的向后兼容,也就是说只有 HTTP/2 没有 HTTP/2.0、HTTP/2.2

5.3 帧

HTTP/2 是基于帧(frame)的协议,采用分帧是为了将重要信息都封装起来,让协议的解析方能够轻松阅读、解析并还原信息。 相比之下,h1 不是基于帧的,而是以文本分隔。因此解析 h1 的请求或响应可能会出现如下问题:

  1. 一次只能处理一个请求或响应,完成以前不能中止解析
  2. 没法预判解析须要多少内存。这会带来一系列问题:你要把一行读到多大的缓冲区里;若是行太长会发生什么;应该增长并从新分配内存,仍是返回 400 错误

从另外一方面来讲,有了帧,处理协议的程序就能预先知道会收到什么。下图是一个 HTTP/2 帧的结构

HTTP/2 帧结构

前 9 个字节对于每一个帧是一致的。解析时只须要读取这些字节,就能够准确地知道在整个帧中指望的字节数。其中每一个字段的说明以下

名称 长度 描述
Length 3 字节 表示帧负载的长度(取值范围为 2^14~2^24-1 字节)。 请注意,214 字节是默认的最大帧大小,若是须要更大的帧,必须在 SETTINGS 帧中设置
Type 1 字节 当前帧类型
Flags 1 字节 具体帧类型的标识
R 1 位 保留位,不要设置,不然可能带来严重后果
Stream Identifier 31 位 每一个流的惟一 ID
Frame Payload 长度可变 真实的帧内容,长度是在 Length 字段中设置的

相比依靠分隔符的 h1,h2 还有另外一大优点:若是使用 h1 的话,你须要发送完上一个请求或者响应,才能发送下一个;因为 h2 是分帧的,请求和响应能够交错甚至多路复用。多路复用有助于解决相似队头阻塞的问题。

h2 有十种不一样的帧类型:

名称 ID (Type) 描述
DATA 0x0 数据帧,传输流的核心内容
HEADERS 0x1 报头帧,包含 HTTP 首部,和可选的优先级参数
PRIORITY 0x2 优先级帧,指示或者更改流的优先级和依赖
RST_STREAM 0x3 流终止帧,容许一端中止流(一般因为错误致使的)
SETTINGS 0x4 设置帧,协商链接级参数
PUSH_PROMISE 0x5 推送帧,提示客户端,服务器要推送些东西
PING 0x6 PING 帧,测试链接可用性和往返时延(RTT)
GOAWAY 0x7 GOAWAY 帧,告诉另外一端,当前端已结束
WINDOW_UPDATE 0x8 窗口更新帧,协商一端将要接收多少字节(用于流量控制)
CONTINUATION 0x9 延续帧,用以扩展 HEADER 数据块

扩展帧 :HTTP/2 内置了名为扩展帧的处理新的帧类型的能力。依靠这种机制,客户端和服务器的实现者能够实验新的帧类型,而无需制定新协议。按照规范,任何客户端不能识别的帧都会被丢弃,因此网络上新出现的帧就不会影响核心协议。固然,若是你的应用程序依赖于新的帧,而中间代理会丢弃它,那么可能会出现问题。

5.4 流

HTTP/2 规范中的流(stream):HTTP/2 链接上独立的、双向的帧序列交换。你能够将流看做在链接上的一系列帧,用来传输一对请求/响应消息。若是客户端想要发出请求,它会开启一个新的流,服务器也在这个流上回复。这与 h1 的请求、响应流程相似,区别在于,由于有分帧,因此多个请求和响应能够交错,而不会互相阻塞。流 ID(帧首部的第 6~9 字节)用来标识帧所属的流。

客户端到服务器的 h2 链接创建以后,经过发送 HEADERS 帧来启动新的流,若是首部须要跨多个帧,可能还发会送 CONTINUATION 帧。

5.4.1 消息

HTTP 消息泛指 HTTP 请求或响应。一个消息至少由 HEADERS 帧(用来初始化流)组成,而且能够另外包含 CONTINUATIONDATA 帧,以及其余的 HEADERS 帧。 下图是普通 GET 请求的示例流程

普通 GET 请求的示例流程

POST 和 GET 的主要差异之一就是 POST 请求一般包含客户端发出的大量数据。下图是 POST 消息对应的各帧可能的样子

普通 POST 请求的示例流程

h1 的请求和响应都分红消息首部和消息体两部分;与之相似,h2 的请求和响应分红 HEADERS 帧和 DATA 帧。HTTP/1 和 HTTP/2 消息的下列差异是须要注意

  1. 一切都是header :h1 把消息分红请求/状态行、首部两部分。h2 取消了这种区分,并把这些行变成了魔法伪首部
  2. 没有分块编码(chunked encoding) :只有在没法预先知道数据长度的状况下向对方发送数据时,才会用到分块。在使用帧做为核心协议的 h2 里,再也不须要分块
  3. 再也不有101的响应 :Switching Protocol 响应是 h1 的边缘应用。它现在最多见的应用可能就是用以升级到 WebSocket 链接。ALPN 提供了更明确的协议协商路径,往返的开销也更小

5.4.2 流量控制

h2 的新特性之一是基于流的流量控制。h1 中只要客户端能够处理,服务端就会尽量快地发送数据,h2 提供了客户端调整传输速度的能力,服务端也一样能够调整传输的速度。

WINDOW_UPDATE 帧用于执行流量控制功能,能够做用在单独某个流上(指定具体 Stream Identifier)也能够做用整个链接 (Stream Identifier 为 0x0),只有 DATA 帧受流量控制影响。初始化流量窗口后,发送多少负载,流量窗口就减小多少,若是流量窗口不足就没法发送,WINDOW_UPDATE 帧能够增长流量窗口大小。流创建的时候,窗口大小默认 65535(2^16-1)字节。

5.4.3 优先级

流的最后一个重要特性是依赖关系。

现代浏览器会尽可能以最优的顺序获取资源,由此来优化页面性能。在没有多路复用的时候,在它能够发出对新对象的请求以前,须要等待前一个响应完成。有了 h2 多路复用的能力,客户端就能够一次发出全部资源的请求,服务端也能够当即着手处理这些请求。由此带来的问题是,浏览器失去了在 h1 时代默认的资源请求优先级策略。假设服务器同时接收到了 100 个请求,也没有标识哪一个更重要,那么它将几乎同时发送每一个资源,次要元素就会影响到关键元素的传输。

h2 经过流的依赖关系来解决上面这个问题。经过 HEADERS 帧和 PRIORITY 帧,客户端能够明确地和服务端沟通它须要什么,以及它须要这些资源的顺序。这是经过声明依赖关系树和树里的相对权重实现的。

  1. 依赖关系 为客户端提供了一种能力,经过指明某些对象对另外一些对象有依赖,告知服务器这些对象应该优先传输
  2. 权重 让客户端告诉服务器如何肯定具备共同依赖关系的对象的优先级

流能够被标记为依赖其余流,所依赖的流完成后再处理当前流。每一个依赖 (dependency) 后都跟着一个权重 (weight),这一数字是用来肯定依赖于相同的流的可分配可用资源的相对比例。

其余时候也能够经过 PRIORITY 帧调整流优先级。

设置优先级的目的是为了让端点表达它所指望对端在并发的多个流之间如何分配资源的行为。更重要的是,当发送容量有限时,能够使用优先级来选择用于发送帧的流。

5.5 服务端推送

升单个对象性能的最佳方式,就是在它被用到以前就放到浏览器的缓存里面。这正是 h2 服务端推送的目的。

5.5.1 推送对象

若是服务器决定要推送一个对象(RFC 中称为『推送响应』),会构造一个 PUSH_PROMISE 帧。这个帧有不少重要属性:

  1. PUSH_PROMISE 帧首部中的流 ID (Promised Stream ID)用来响应相关联的请求。推送的响应必定会对应到客户端已发送的某个请求。若是浏览器请求一个主体 HTML 页面,若是要推送此页面使用的某个 JavaScript 对象,服务器将使用请求对应的流 ID 构造 PUSH_PROMISE 帧。
  2. PUSH_PROMISE 帧的首部块与客户端请求推送对象时发送的首部块是类似的。因此客户端有办法放心检查将要发送的请求。
  3. 被发送的对象必须确保是可缓存的。
  4. :method 首部的值必须确保安全。安全的方法就是幂等的那些方法,这是一种不改变任何状态的好办法。例如,GET 请求被认为是幂等的,由于它一般只是获取对象,而 POST 请求被认为是非幂等的,由于它可能会改变服务器端的状态。
  5. 理想状况下,PUSH_PROMISE 帧应该更早发送,应当早于客户端接收到可能承载着推送对象的 DATA 帧。假设服务器要在发送 PUSH_PROMISE 以前发送完整的 HTML,那客户端可能在接收到 PUSH_PROMISE 以前已经发出了对这个资源的请求。h2 足够健壮,能够优雅地解决这类问题,但仍是会有些浪费。
  6. PUSH_PROMISE 帧会指示将要发送的响应所使用的流 ID

若是客户端对 PUSH_PROMISE 的任何元素不满意,就能够按照拒收缘由选择重置这个流(使用 RST_STREAM),或者发送 PROTOCOL_ERROR (在 GOAWAY 帧中)。常见的状况是缓存中已经有了这个对象。

假设客户端不拒收推送,服务端会继续进行推送流程,用 PUSH_PROMISE 中指明 ID 对应的流来发送对象

服务端推送消息处理

5.5.2 选择要推送的资源

若是服务器接收到一个页面的请求,它须要决定是推送页面上的资源仍是等客户端来请求。决策的过程须要考虑到以下方面

  1. 资源已经在浏览器缓存中的几率
  2. 从客户端看来,这些资源的优先级 (参见 5.4.3 节)
  3. 可用的带宽,以及其余相似的会影响客户端接收推送的资源

若是服务器选择正确,那就真的有助于提高页面的总体性能,反之则会损耗页面性能。

5.6 首部压缩

现代网页平均有不少请求,这些请求之间几乎没有新的的内容,这是极大的浪费。

首部列表 (Header List) 是零个或多个首部字段 (Header Field) 的集合。当经过链接传送时,首部列表经过压缩算法(即下文 HPACK) 序列化成首部块 (Header Block),不用 GZIP 是由于它有泄漏加密信息的风险。HPACK 是种表查找压缩方案,它利用霍夫曼编码得到接近 GZIP 的压缩率。

而后,序列化的首部块又被划分红一个或多个叫作首部块片断 (Header Block Fragment) 的字节序列,并经过 HEADERSPUSH_PROMISE,或者 CONTINUATION 帧进行有效负载传送。

假设客户端按顺序发送以下请求首部:

Header1: foo
Header2: bar
Header3: bat

当客户端发送请求时,能够在首部数据块中指示特定首部及其应该被索引的值。它会建立一张表:

索引 首部名称
62 Header1 foo
63 Header2 bar
64 Header3 bat

若是服务端读到了这些请求首部,它会照样建立一张表。客户端发送下一个请求的时候, 若是首部相同,它能够直接发送:62 63 64 ,服务器会查找先前的表格,并把这些数字还原成索引对应的完整首部。首部压缩机制中每一个链接都维护了本身的状态。

HPACK 的实现比这个要复杂得多,好比:

  1. 请求端和响应端各维护了两张表格。其中之一是动态表,建立方法和上面差不 多。另外一张是静态表,它由 61 个最多见的首部的键值组合而成。例如 :method: GET 在静态表中索引为 2。按规定,静态表包含 61 个条目,因此上例索引编号从 62 开始。
  2. 关于字段如何索引,有不少控制规则:

    1. 发送索引编号和文本值仅发送文本值,不对它们进行索引(对于一次性或敏感首部)
    2. 发送索引的首部名,值用文本表示,但不进行索引处理(如:path: /foo.html,其值每次都不一样)
    3. 发送索引过的首部名和值(如上例中的第二个请求)
  3. 使用打包方案的整数压缩,以实现极高的空间效率
  4. 利用霍夫曼编码表进一步压缩字符串

5.7 线上传输

线上传输的 h2 信息是通过压缩的二进制数据。

一个简单的GET请求

下面是一个简单的 h2 的 get 请求

:authority: www.akamai.com
:method: GET
:path: /
:scheme: https
accept: text/html,application/xhtml+xml,...
accept-language: en-US,en;q=0.8
cookie: sidebar_collapsed=0; _mkto_trk=...
upgrade-insecure-requests: 1
user-agent: Mozilla/5.0 (Macintosh;...

下面是 h2 的一个响应

:status: 200
cache-control: max-age=600
content-encoding: gzip
content-type: text/html;charset=UTF-8
date: Tue, 31 May 2016 23:38:47 GMT
etag: "08c024491eb772547850bf157abb6c430-gzip"
expires: Tue, 31 May 2016 23:48:47 GMT
link: <https://c.go-mpulse.net>;rel=preconnect
set-cookie: ak_bmsc=8DEA673F92AC...
vary: Accept-Encoding, User-Agent
x-akamai-transformed: 9c 237807 0 pmb=mRUM,1
x-frame-options: SAMEORIGIN

在这个响应中,服务器表示请求已成功受理(状态码 200),设置了 cookie(cookie 首部),表示返回的内容使用 gzip 压缩(content-encoding 首部)

6. HTTP/2性能

HTTP/2 大部分状况下传输 web 页面比 HTTP/1.1 快。

  1. 对于包含不少小型资源的页面,h2 加载页面的时间比 h1 更短。这是由于 h1 下(有 6 个 TCP 链接)服务器只能并行发送 6 个资源(因为队头阻塞),而 h2 下多个流(stream)能够共用链接。进一步说,随着网络条件变差,h1 和 h2 下页面加载时间(PLT)都会增长;可是 h2 因为单链接,若是惟一的链接发生了丢包,全部工做都会受影响。
  2. 对于包含少许大型资源的页面,在全部网络条件下,h1 性能上都比 h2 表现要好。这个多少使人感到意外的结果是初始拥塞窗口致使的。若是开启 6 个链接,h1 的初始拥塞窗口大小其实是 h2 的 6 倍。所以在会话开始阶段,h2 的链接窗口还没有增加到最佳值,但 h1 早就能更快地传输更多数据了。这个问题目前仍在解决,由于它致使初始拥塞窗口对 h2 而言过小,然而对 h1 而言又太大。 此外,h2 比 h1 更容易受丢包的影响。
  3. 对于包含一些极大型资源的 Web 页面,二者没有任何差别。h2 的初始拥塞窗口劣势被总体下载时长掩盖了,多路复用此时也再也不具备优点。

6.1 客户端实现

网络条件相同,使用不一样浏览器客户端,一样的网站页面加载性能可能差异很大。

  1. 协议的具体实现很重要
  2. 并不是全部请求在任何状况下都会从 HTTP/2 受益,即使如此,URL 使用 h2 后性能提高的比例也依旧高于降低的比例

6.2 延迟

延迟是指数据包从一个端点到另外一个端点所花的时间。有时,它也表示数据包到达接收方而后返回发送方所需的时间,又称为往返时延(RTT),长度通常以毫秒计。

影响延迟的因素众多,但有两个是最重要的:端点间的距离,以及所用传输介质

两点之间的网线不会是笔直的,另外各类网关、路由器、交换机以及移动基站等(也包括服务器应用自己)都会增长延迟

6.3 丢包

若是网络中传输的数据包没有成功到达目的地,就会发生丢包,这一般是由网络拥堵形成的。

频繁丢包会影响 h2 的页面传输,主要是由于 h2 开启单一 TCP 链接,每次有丢包/拥堵时,TCP 协议就会缩减 TCP 窗口。

若是 TCP 流上丢了一个数据包,那么整个 h2 链接都会停顿下来,直到该数据包重发并被接收到。

6.4 服务端推送

服务端推送让服务器具有了在客户端请求以前就推送资源的能力。 测试代表,若是合理使用推送,页面渲染时间能够减小 20%~50%。

然而,推送也会浪费带宽,这是由于服务端可能试图推送那些在客户端已经缓存的资源,致使客户端收到并不须要的数据。客户端确实能够发送 RST_STREAM 帧来拒绝服务器的 PUSH_PROMISE 帧,可是 RST_STREAM 并不会即刻到达,因此服务器仍是会发送一些多余的信息。

若是用户第一次访问页面时,就能向客户端推送页面渲染所需的关键 CSS 和 JS 资源,那么服务端推送的真正价值就实现了。不过,这要求服务器端实现足够智能,以免『推送承诺』(push promise)与主体 HTML 页面传输竞争带宽。

理想状况下,服务端正在处理 HTML 页面主体请求时才会发起推送。有时候,服务端须要作一些后台工做来生成 HTML 页面。这时候服务端在忙,客户端却在等待,这正是开始向客户端推送所需资源的绝佳时机。

在后台处理的同时进行推送

6.5 首字节时间

首字节时间(TTFB)用于测量服务器的响应能力。是从客户端发起 HTTP 请求到客户端浏览器收到资源的第一个字节所经历的时间。由 socket 链接时间、发送 HTTP 请求所需时间、收到页面第一个字节所需时间组成。

h1 中,客户端针对单个域名在每一个链接上依次请求资源,并且服务器会按序发送这些资源。客户端只有接收了以前请求的资源,才会再请求剩下的资源,服务器接着继续响应新的资源请求。这个过程会一直重复,直到客户端接收完渲染页面所需的所有资源。

与 h1 不一样,经过 h2 的多路复用,客户端一旦加载了 HTML,就会向服务器并行发送大量请求。相比 h1,这些请求得到响应的时间之和通常会更短;可是由于是请求是同时发出的,而单个请求的计时起点更早,因此 h2 统计到的 TTFB 值会更高。

HTTP/2 比 h1 确实作了更多的工做,其目的就是为了从整体上提高性能。下面是一些 h1 没有,但 h2 实现了的

  1. 窗口大小调节
  2. 依赖树构建
  3. 维持首部信息的静态 / 动态表
  4. 压缩 / 解压缩首部
  5. 优先级调整(h2 容许客户端屡次调整单一请求的优先级)
  6. 预先推送客户端还没有请求的数据流

下图是使用 h1 和 h2 加载同一个页面的加载时序对比,整体来讲 h2 体验更好

h1 与 h2 请求的时间序列

6.6 第三方资源

许多网站会使用各类统计、跟踪、社交以及广告平台,就会引入各类第三方的资源。

  1. 第三方请求每每经过不一样域名发送;因为浏览器须要解析 DNS、创建 TCP 链接、协商 TLS,这将严重影响性能;
  2. 由于第三方资源在不一样域名下,因此请求不能从服务端推送、资源依赖、请求优先级等 h2 特性中受益。这些特性仅是为请求相同域名下的资源设计的;
  3. 你没法控制第三方资源的性能,也没法决定它们是否会经过 h2 传输;

6.7 HTTP/2反模式

h1 下的一些性能调优办法在 h2 下会起到副作用。下面列出了一些用于优化 h1 请求的经常使用技巧,并标注了 h2 方面的考虑。

名称 描述 备注
资源合并 把多个文件(JavaScript、CSS) 合成一个文件,以减小 HTTP 请求 在 HTTP/2 下这并不是必要,由于请求的传输字节数和时间成本更低,虽然这种成本仍然存在
极简化 去除 HTML、JavaScript、CSS 这类文件中无用的代码 很棒的作法,在 HTTP/2 下也要保留
域名拆分 把资源分布到不一样的域名上面去,让浏览器利用更多的 socket 链接 HTTP/2 的设计意图是充分利用单个 socket 链接,而拆分域名会违背这种意图。建议取消域名拆分,但请注意本表格以后的附注框会介绍这个问题相关的各类复杂状况
禁用 cookie 的域名 为图片之类的资源创建单独的域名,这些域名不用 cookie,以尽量减小请求尺寸 应该避免为这些资源单独设立域名(参见域名拆分),但更重要的是,因为 HTTP/2 提供了首部压缩,cookie 的开销会显著下降
生成精灵图 把多张图片拼合为一个文件,使用 CSS 控制在 Web 页面上展现的部分 与极简化相似,只不过用 CSS 实现这种效果的代价高昂;不推荐在 HTTP/2 中使用

6.7.1 生成精灵图和资源合并/内联

精灵图(spriting)是指把不少小图片拼合成一张大图,这样只需发起一个请求就能够覆盖多个图片元素。在 HTTP/2 中,针对特定资源的请求再也不是阻塞式的,不少请求能够并行处理;就性能而言,生成精灵图已失去意义,由于多路复用和首部压缩去掉了大量的请求开销。

与之相似,小的文本资源,例如 JS 和 CSS,会依照惯例合并成一份更大的资源,或者直接内嵌在主体 HTML 中,这也是为了减小客户端-服务器链接数。这种作法有个问题是,那些小的 CSS 或 JS 自身也许可缓存,但若是它们内嵌在不可缓存的 HTML 中的话,固然也就不可缓存了。把不少小的 JS 脚本合并成一个大文件可能仍旧对 h2 有意义,由于这样能够更好地压缩处理并节省 CPU。

6.7.2 域名拆分

域名拆分(sharding)是为了利用浏览器针对每一个域名开启多个链接的能力来并行下载资源。对于包含大量小型资源的网站,广泛的作法是拆分域名,以利用现代浏览器针能对每一个域名开启 6 个链接的特性,充分利用可用带宽。

由于 HTTP/2 采起多路复用,因此域名拆分就不是必要的了,而且反而会让协议力图实现的目标落空。比较好的办法就是继续保持当前的域名拆分,可是确保这些域名共享同一张证书 [ 通配符 / 存储区域网络(SAN)],并保持服务器 IP 地址和端口相同,以便从浏览器网络归并(network coalescence)中收益,这样能够节省为单个域名链接创建的时间。

6.7.3 禁用cookie的域名

在 HTTP/1 下,请求和响应首部从不会被压缩。随着时间推移,首部大小已经增加了,超过单个 TCP 数据包的 cookie 能够说司空见惯。所以,在内容源和客户端之间来回传输首部信息的开销可能形成明显的延迟。

所以,对图片之类不依赖于 cookie 的资源,设置禁用 cookie 的域名是个合理的建议。

可是 HTTP/2 中,首部是被压缩的,而且客户端和服务器都会保留『首部历史』,避免重复传输已知信息。因此,若是你要重构站点,大可没必要考虑禁用 cookie 的域名,这样能减小不少包袱。

静态资源也应该从同一域名提供;使用与主页面 HTTP 相同的域名,消除了额外的 DNS 查询以及(潜在的)socket 链接,它们都会减慢静态资源的获取。把阻塞渲染的资源放在一样的域名下,也能够提高性能。

6.7.4 资源预取

资源预取也是一项 Web 性能优化手段,它提示浏览器只要有可能就继续下载可缓存资源,并把这些资源缓存起来。尽管如此,若是浏览器很忙,或者资源下载花的时间太 长,预取请求将会被忽略。资源预取能够在 HTML 中插入 link 标签实现:

<link rel="prefetch" href="/important.css">

也能够使用 HTTP 响应中的 Link 首部: Link: </important.css>; rel=prefetch

资源预取与 h2 引入的服务端推送并没多少关联。服务端推送用于让资源更快到达浏览器, 而资源预取相比推送的优势之一是,若是资源已经在缓存里,浏览器就不会浪费时间和带宽重复请求它。因此,能够把它看做 h2 推送的补充工具,而不是将被替代的特性。

6.8 现实状况中的性能

网络丢包是 h2 的命门,一次丢包机会就会让它的全部优化泡汤。

7. HTTP/2 实现

7.1 桌面Web浏览器

全部浏览器在进行 HTTP/2 传输时都须要使用 TLS(HTTPS),即便事实上HTTP/2 规范自己并无强制要求 TLS。这个缘由是:

  1. 从以前对 WebSocket 和 SPDY 的实验看来,使用 Upgrade 首部,经过 80 端口(明文的 HTTP 端口)通讯时,通讯链路上代理服务器的中断等因素会致使很是高的错误率。若是基于 443 端口(HTTPS 端口)上的 TLS 发起请求,错误率会显著下降,而且协议通讯也更简洁。
  2. 人们愈来愈相信,考虑到安全和隐私,一切都应该被加密。HTTP/2 被视为一次推进全网加密通讯发展的机会。

7.1.2 禁用HTTP/2

HTTP/2 毕竟是新鲜事物,如今不少浏览器都支持启用或禁用 h2。

7.1.3 支持 HTTP/2 服务端推送

服务端推送是 h2 中最使人兴奋也最难正确使用的特性之一,如今全部的主流浏览器都已经支持了此特性。

7.1.4 链接归并

若是须要创建一个新链接,而浏览器支持链接归并,那么经过复用以前已经存在的链接,就可以提高请求性能。这意味着能够跳过 TCP 和 TLS 的握手过程,改善首次请求新域名的性能。若是浏览器支持链接归并,它会在开启新链接以前先检查是否已经创建了到相同目的地的链接。

相同目的地具体指的是:已经存在链接,其证书对新域名有效,此域名能够被解析成那个链接对应的 IP 地址。若是上述条件都知足,那么浏览器会在已创建的链接上向该域名发起 HTTP/2 请求。

7.2 服务器、代理以及缓存

若是要经过 h2 传输内容,咱们有几个选择。支持 HTTP/2 的网络设施大体有如下两类。

Web服务器 :一般所说的提供静态和动态内容服务的程序。

代理/缓存 :通常处在服务器和最终用户之间,能够提供缓存以减轻服务器负载,或进行额外加工。许多代理也能扮演 Web 服务器的角色。

在选择 HTTP/2 服务器时,咱们须要检查、评估一些关键点。除了基本的通用性能、操做系统支持、学习曲线、可扩展性以及稳定性,还应当关注 Web 请求的依赖项优先级,以及对服务端推送的支持。

7.3 内容分发网络 CDN

内容分发网络(CDN)是反向代理服务器的全球性分布式网络,它部署在多个数据中心。CDN 的目标是经过缩短与最终用户的距离来减小请求往返次数,以此为最终用户提供高可用、高性能的内容服务。

大多数主流 CDN 是支持 HTTP/2 的,选择 CDN 时主要考虑的两点是:对服务端推送的支持,以及它们处理优先级的方式。这两点对现实世界中的 Web 性能影响重大。

8. HTTP/2调试

8.1 chrome devtools 可视化

Chrome 开发者工具中的 Network 栏,有助于简单直观地跟踪客户端和服务端的通信,它 按下面表格的形式展现了若干信息:

  1. 资源名
  2. 资源大小
  3. 状态码
  4. 优先级
  5. 总加载时间
  6. 使用时间线方式分解加载时间

打开 devtools 的 Network 栏,鼠标放在瀑布流 Waterfall 的资源上,就会看到资源加载过程当中各个阶段的详细时间

  1. Connection Setup (链接设置)

    1. Queueing :请求被渲染引擎或者网络层延迟的时间,浏览器在如下状况下对请求排队

      • 存在更高优先级的请求。
      • 此源已打开六个 TCP 链接,达到限值。 仅适用于 HTTP/1.0 和 HTTP/1.1
      • 浏览器正在短暂分配磁盘缓存中的空间
  2. Connection Start (开始链接阶段)

    1. Stalled :请求可能会因 Queueing 中描述的任何缘由而中止
    2. Proxy negotiation :浏览器与代理服务器协商请求花费的时间
    3. DNS Lookup :浏览器解析请求的 IP 地址花费的时间
  3. Request/Response (请求 / 响应)

    1. Request Sent :发送请求包含的数据花费的时间
    2. Waiting (TTFB) :等待初始响应花费的时间,也就是所说的首字节时间;这个数字包括等待服务器传输响应的时间,以及往返服务器的延迟
    3. Content Download :接收响应的数据所花费的时间
  4. Explanation (总时间)
  5. 其余

    1. ServiceWorker Preparation :浏览器正在启动 Service Worker
    2. Request to ServiceWorker :正在将请求发送到 Service Worker
    3. Receiving Push :浏览器正在经过 HTTP/2 服务器推送接收此响应的数据
    4. Reading Push :浏览器正在读取以前收到的本地数据

9. 展望将来

HTTP/2 的弱点之一就是依赖主流 TCP 实现。在 3.1.3 节中已经讨论过,TCP 链接受制于 TCP 慢启动、拥塞规避,以及不合理的丢包处理机制。用单个连接承载页面涉及的全部资源请求,就能享受多路复用带来的好处;然而面对 TCP 层级的队首阻塞时,咱们仍是一筹莫展。因此 Google 开发的 QUIC 采纳了 HTTP/2 的优势,而且避免了这些缺点。


网上的帖子大多深浅不一,甚至有些先后矛盾,在下的文章都是学习过程当中的总结,若是发现错误,欢迎留言指出~

推介阅读:

  1. HTTP2 详解 | Wangriyu’s Blog

PS:欢迎你们关注个人公众号【前端下午茶】,一块儿加油吧~

另外能够加入「前端下午茶交流群」微信群,长按识别下面二维码便可加我好友,备注加群,我拉你入群~

相关文章
相关标签/搜索