NGINX Plus R15还包含对 HTTP/2 服务器推送的支持。
我们很高兴地宣布, 2018 年 2 月 20 日发布的NGINX 1.13.9已支持 HTTP/2 服务器推送。 对于 NGINX Plus 用户,HTTP/2 服务器推送支持将包含在即将于 2018 年 4 月发布的NGINX Plus R15版本中。
服务器推送是在 HTTP/2 规范中定义的,它允许服务器预先将资源推送到远程客户端,预测客户端可能很快会请求这些资源。 通过这样做,您可以将页面加载操作中的 RTT(往返时间 - 请求和响应所需的时间)数量减少一个或多个,从而为用户提供更快的响应。
服务器推送可用于向客户端提供呈现网页所需的样式表、图像和其他资源。 您应该注意仅推送所需的资源;不要推送客户端可能已经缓存的资源。
在这篇博文中,我描述:
nghttp
)链接
标头自动推送内容要在页面加载时推送资源,请使用http2_push
指令,如下所示:
服务器 { # 确保服务器启用了 HTTP/2 监听 443 ssl http2 ; ssl_certificate ssl/certificate.pem; ssl_certificate_key ssl/key.pem; root /var/www/html; # 每当客户端请求 demo.html 时,也会推送 # /style.css、/image1.jpg 和 /image2.jpg location = /demo.html { http2_push /style.css; http2_push /image1.jpg; http2_push /image2.jpg; } }
您可以使用以下两种方法之一轻松验证服务器推送是否有效:
nghttp
下面以 Google Chrome 为例,介绍如何使用 Web 浏览器中的开发人员工具来验证服务器推送是否有效。 图中,Chrome 开发者工具的网络选项卡上的启动器列表明,作为/demo.html请求的一部分,多个资源被推送到客户端。
nghttp
)除了 Web 浏览器工具之外,您还可以使用nghttp2.org项目中的nghttp
命令行客户端来验证服务器推送是否有效。 您可以从GitHub下载nghttp
命令行客户端,或者在可用的情况下安装适当的操作系统包。 对于 Ubuntu,使用nghttp2-client
包。
在输出中,星号(*)标记了服务器推送的资源。
$ nghttp -ans https://example.com/demo.html id 响应结束请求开始进程代码大小请求路径 13 +84.25ms +136us 84.11ms 200 492 /demo.html 2 +84.33ms * +84.09ms 246us 200 266 /style.css 4 +261.94ms * +84.12ms 177.83ms 200 40K /image2.jpg 6 +685.95ms * +84.12ms 601.82ms 200 173K /image1.jpg
在许多情况下,在 NGINX 配置文件中列出您希望推送的资源是不方便的,甚至是不可能的。 为此,NGINX 还支持拦截Link
预加载标头的约定,然后推送这些标头中标识的资源。 要启用预加载,请在配置中包含http2_push_preload
指令:
服务器 { # 确保服务器启用了 HTTP/2 监听 443 ssl http2 ; ssl_certificate ssl/certificate.pem; ssl_certificate_key ssl/key.pem; root /var/www/html; # 拦截链接标头并发起请求的推送 location = /myapp { proxy_pass http://upstream; http2_push_preload on; } }
例如,当 NGINX 作为代理运行时(对于 HTTP、FastCGI 或其他流量类型),上游服务器可以在其响应中添加如下Link
标头:
链接:</style.css>; as=style; rel=preload
NGINX 拦截该标头并开始/style.css的服务器推送。 链接
标头中的路径必须是绝对路径 - 不支持像./style.css这样的相对路径。 该路径可以选择包含查询字符串。
要推送多个对象,您可以提供多个Link
标头,或者更好的是,将所有对象包含在逗号分隔的列表中:
链接:</style.css>; as=style; rel=preload,</favicon.ico>; as=image; rel=preload
如果你不想让 NGINX 推送预加载的资源,请在标头中添加nopush
参数:
# 资源未推送Link: </nginx.png>; as=image; rel=preload; nopush
当http2_push_preload
启用时,您还可以通过在 NGINX 配置中设置响应标头来启动预加载服务器推送:
add_header 链接 "</style.css>; as=style; rel=preload";
HTTP/2 规范并未解决确定是否推送资源的难题。 显然,如果您知道客户端可能需要该资源并且不太可能已经缓存该资源,那么最好只将资源推送给客户端。
一种可能的方法是仅在客户第一次访问网站时向其推送资源。 例如,您可以测试会话 cookie 是否存在,并有条件地设置Link
标头,这样仅当不存在会话 cookie 时才会预加载资源。
假设客户端行为良好并在后续请求中包含 cookie,则通过以下配置,NGINX 在每个浏览器会话中仅将资源推送到客户端一次:
服务器 {
listen 443 ssl http2 default_server;
ssl_certificate ssl/certificate.pem;
ssl_certificate_key ssl/key.pem;
root /var/www/html;
http2_push_preload on;
location = /demo.html {
add_header Set-Cookie "session=1";
add_header Link $resources;
}
}
map $http_cookie $resources {
"~*session=1" "";
default "</style.css>; as=style; rel=preload, </image1.jpg>; as=image; rel=preload, </image2.jpg>; as=image; rel=preload";
}
为了衡量服务器推送的效果,我们创建了一个简单的测试页面/demo.html ,它引用了一个单独的样式表/style.css 。 样式表进一步引用了两幅图像。 我们使用三种不同的配置测试了页面加载时间:
GET
(无优化)——浏览器在发现需要资源时才加载资源链接
标头)包含在第一个响应中,以告知浏览器加载依赖项我们使用 HTTP、HTTPS 或 HTTP/2 对每种配置进行了多次测试运行。 前两个配置适用于所有三种协议,服务器推送仅适用于 HTTP/2。
该行为是使用 Chrome 开发者工具来测量的。 对每种配置的最常见行为进行了评估和平均,并将时间与链路的 RTT(使用ping
测量)相关联,以说明每种方法的机械效果。
GET
操作大约在 1 RTT 内完成。GET
请求的 0.5 RTT。keepalive_timeout
和http2_idle_timeout
用于快速关闭保持连接。这次测试刻意做得简单,是为了突出预加载提示和服务器推送的机制。 在简单情况下,服务器推送比预加载提示提供了 1-RTT 的改进,与未优化的顺序GET
请求和依赖资源的发现相比,改进更大。
更现实的用例有更多的变量:多个依赖资源,多个来源,甚至通过推送已经缓存或不立即需要的资源而浪费带宽的可能性。 浏览器不一致也会影响性能。 您的里程肯定会与这个简单的测试有所不同。
例如,Chrome 团队发布了一些关于何时部署服务器推送的详细建议,并在更复杂的网站上进行了测量,以比较无优化、预加载提示和通过 HTTP/2 进行服务器推送的效果。 对于任何考虑在生产中部署 HTTP/2 服务器推送的人来说,他们的《HTTP/2 推送经验规则》报告都值得一读。
务实的结论是,如果您可以提前确定需要哪些资源,那么让上游服务器发送预加载提示会带来真正的好处。 推送这些资源的额外好处虽小但可以衡量,但可能会导致带宽浪费和所需资源的延迟。 您应该仔细测试和监控任何服务器推送配置。
以下信息部分基于 Jake Archibald 的非常详细的“HTTP/2 推动比我想象的更艰难”博客文章中的研究。
HTTP/2 服务器推送通常用于在客户端请求资源时预先发送依赖资源。 例如,如果客户端请求网页,服务器可能会将相关的样式表、字体和图像推送给客户端。
当客户端建立 HTTP/2 连接时,服务器可以选择通过该连接启动一个或多个服务器推送响应。 这些推送发送客户端未明确请求的资源。
客户端可以拒绝推送(通过发送RST_STREAM
帧)或接受推送。 客户端将推送的内容存储在与 HTTP/2 连接相关联的本地“推送缓存”中。
稍后,当客户端使用已建立的 HTTP/2 连接请求资源时,它会检查连接的推送缓存中是否有对该请求的已完成或正在传输的响应。 它优先使用缓存的资源,而不是对该资源发出新的 HTTP/2 请求。
任何推送的资源都会保留在每个连接的推送缓存中,直到 (a) 被使用或 (b) HTTP/2 连接关闭:
这有几个含义:
您可以在 Jake Archibald 的“HTTP/2 推送比我想象的还要艰难”博客文章中查看更详细的问题列表。
HTTP/2 服务器推送是一项有趣的功能。 确保彻底测试您的 HTTP/2 服务器推送配置,并准备在提供更可预测的缓存感知行为的情况下回退到预加载提示。
“这篇博文可能引用了不再可用和/或不再支持的产品。 有关 F5 NGINX 产品和解决方案的最新信息,请探索我们的NGINX 产品系列。 NGINX 现在是 F5 的一部分。 所有之前的 NGINX.com 链接都将重定向至 F5.com 上的类似 NGINX 内容。”