2016-07-17

[译] HTTP2 Server Push 实践:单 Link 报头包含多资源场景

原文作者: John Graham-Cumming
原文地址: https://blog.cloudflare.com/http-2-server-push-with-multiple-assets-per-link-header/
译文地址: http://www.wemlion.com/post/http-2-server-push-with-multiple-assets-per-link-header
本文由 文蔺 翻译,转载请保留此声明。
著作权属于原作者,本译文仅用于学习、研究和交流目的,请勿用于商业目的。

译者注

译者在做自己的一个小工具(抓取博客的 Chrome 扩展)的时候,使用 jQuery 辅助作为 DOM 解析器,为了避免加载图片、脚本、样式表等无用的资源,在将字符串传给 的时候,先对字符串中的相关标签进行了处理。

但遇到某个网站的时候,一直疑惑不解,明明已经做了替换,但通过 Chrome Devtools 能看到,部分资源还是会下载。几经折腾,发现还是因为自己懂得太少了。

查看请求该页面时的 header,可以看到了如下信息:

于是,大概能猜出来上述问题的原因。这有点类似如一些站点会使用的 标签(顺带一句,截至 2016 年 7 月 17 日,caniuse 数据:China = 26.83%;Global = 44.59%)。

于是深入挖掘了一下。来看看 W3C 标准是怎么说的(同样由译者翻译):

例如,应用可以使用 preload 关键词,提前、高优先级、不阻塞渲染地拉取的 CSS 资源,它会在适当的时候被使用:

例一:使用标签

例二:使用 HTTP Header

上面的例子说明,资源可以通过声明性标记、HTTP header link 来指定,或者使用 JavaScript 预定。

记录以下资源备忘:

译文标题为意译,原标题为 ,恐有不当,特此说明。

另,为加强理解 报头与 二者,译文正文后附有 W3C preload 标准中 “Server Push (HTTP/2)” 一节译文。或有助于读懂本文。

注: 译文中凡是 “link 响应头” 的名词,英文为 “Link header”,翻译为“响应头 Link 字段”或许更恰当。

正文

四月份的时候,我们宣布为所有的 CloudFlare 网站添加了 HTTP/2 Server Push 试验性支持。这样做是为了让客户能够在该新功能的基础上进行迭代。

CC BY 2.0image by https://www.flickr.com/photos/mryipyop/

我们的 Server Push 实现,利用了 HTTP 报头,这在 W3C Preload 工作草案中有详细描述。

同样,我们还展示了,如何在 PHP 代码 中实现 Server Push,许多人已经开始测试、使用该特性了。

然而,我们的初始版本有很严格的限制:使用 Server Push,则每个 报头中,最多只能指定一个资源,另外,很多 CMS 和 Web 开发平台都不允许存在多个 报头。

现在该问题已得到解决,多个资源可以通过单个 报头推送。修改是实时生效的,如果你的浏览器支持 HTTP/2 的话,你正在阅读的本文就使用了该方式推送资源。

当 CloudFlare 读到源服务器(origin web server)的 报头时,它从中移除其中已通过 Server Push 推送给浏览器的资源。这样一来,要 debug 和 Server Push 问题就困难了,所以我们又加上了一个叫做 的报头,它包含已经推送过的资源。

举个例子。打开最近的这篇博客,源服务器就会发送以下报头:

CloudFlare 决定使用使用 HTTP/2 Server Push 推送这些资源:

响应通过 CloudFlare 的时候,这些资源将从 报头终移除,通过 Server Push 推送,并被添加到 报头中:

在 Google Chrome 金丝雀版本(Google Chrome Canary)的开发者视图中可以看得很清楚。(译者注:翻译本文时译者使用的 Chrome 51.0.2704.106 m (64-bit) 确实无法看到 Push 信息,建议使用最新金丝雀版本一探究竟。)

结尾

如果你在使用 Server Push,请和我们联系。推送不同类型的资源(图片 vs 样式表 vs 脚本)、解决最佳的推送数量(目前我们支持 每页最多 50 条资源),我们对相关经验十分感兴趣。

附: Server Push (HTTP/2)

原文地址: https://w3c.github.io/preload/#server-push-http-2

HTTP/2 ([RFC7540]) 允许服务器先发制人地向客户端发送(“推送”)响应。推送的响应(pushed response)在语义上(semantically)与服务器对请求的响应(server responding to a request)是等价的,而且类似于预加载的响应(preloaded response);它会被浏览器保存,在匹配到应用启动的其他请求的时候被执行。像这样的,从应用角度来看,使用预加载和服务器推送的请求,并无差别。

服务器可能会为应用定义的那些有权限的 preload link 资源启用服务器推送。对那些声明的 preload link 资源来说,启用服务器推送消除了客户端和服务器之间的请求往返。可选地,如果某个通过 报头(RFC5988)声明的资源不希望使用服务器推送,开发者*可以使用 目标属性(RFC5988] section 5.4) 向服务器提供一个选择性退出的信号。示例如下:

例三

Note:上面的示例,向一个可以使用 HTTP/2 推送的服务器提示, 不应被推送(例如,来源方可能有额外信息显示其已经存在于缓存中),而 应当可以作为服务器推送的候选资源。

preload link 启用服务器推送是一个可选的优化项。比方说,服务器可能不会启用推送,如果它认为响应在客户端缓存中可以拿到:客户端会处理预加载指令,检查相关缓存,如果找不到资源则会发送请求。另外,服务器可能因为运维问题而不会启用推送,比如说可用服务器资源或者其他考量。最后,服务器推送的启用取决于协议的 HTTP/2 连接设置:客户端可能会限制或完全禁用服务器推送的使用。应用程序不应当依赖于服务器推送的可用性及其使用。