HTTP/2 服务器推送 - Nginx 1.13.9 中的服务器推送

yufei       6 年, 4 月 前       1306

Nginx 1.13.9 这个版本是在 2018 年 2 月 20 日发布的,包含了对 HTTP/2 服务器推送的支持。对于 NGINX Plus 用户,也会在 2018 年 4 月即将推出的 NGINX Plus R15 版本中包含 HTTP/2 服务器推送支持。

服务器推送 ( 在 HTTP/2 规范 中定义 )允许服务器先发制人地将资源推送到远程客户端,预计客户端可能很快就会请求这些资源。通过预先推送资源,我们可以在一个 RTT 或更多 RTT 页面加载操作中减少 RTT 的数量 ( 往返时间 - 请求和响应所需的时间 ) ,从而为用户提供更快的响应.

服务器推送可以预先给客户端发送样式表,图像和呈现网页所需的其它资源。而我们应该注意只推送所需的资源;不要推送客户端可能已经缓存的资源

本章节,我们会学习 Nginx 1.13.9 版本中提供的 HTTP/2 服务器推送知识的方方面面,包括配置和一些推送指令。

配置 HTTP/2 服务器推送

如果要将资源与请求的页面一起推送,则需要使用 http2_push 指令。使用方法如下

server {
    # 确保服务器开启了 HTTP/2 支持        
    listen 443 ssl http2;

    ssl_certificate ssl/certificate.pem;
    ssl_certificate_key ssl/key.pem;

    root /var/www/html;

    # 当客户端请求 index.html 时,同时推送
    # /img1.jpg  /img2.jpg
    # 资源给客户端
    location = /index.html {
        http2_push /img1.jpg;
        http2_push /img2.jpg;
    }
}

http2_push 指令

http2_push 指令用于推送一个资源给远程的客户端,该指令有且只能有一个参数,那就是资源的请求路径 ( 相对于当前的 location 的目录 )

http2_push path_to_resource;

检查 HTTP/2 推送是否成功

我们可以简单的使用下面两种方法来验证刚刚我们配置的服务器推送是否有效

  • 现代浏览器中的开发者工具,特别是 Google Chrome 开发者工具中的 「 网络 」 面板
  • HTTP/2 命令行工具,例如 nghttp

使用开发者工具 ( Google Chrome ) 验证

我们以 Google Chrome 浏览器为例,介绍如何使用 Web 浏览器中的 「 开发者工具 」验证服务器推送是否生效

下图中, Chrome 「 开发者工具 」中的 「 网络 」 选项卡上的 「 启动器 ( Initiator ) 」 列表示,作为 /index.html 请求的一部分,已将多个资源推送到客户端

使用命令行工具 ( nghttp ) 验证

除了 Web 浏览器工具,我们还可以使用 nghttp2.org 项目中的nghttp命令行客户端来验证服务器推送是否生效。

您可以从 GitHub 下载 nghttp 命令行客户端,或者在可用的情况下安装相应的操作系统软件包

  • 对于 Ubuntu,请使用 nghttp2-client 软件包
  • 对于 Mac,可以使用 brew install nghttp2 安装

使用方式一般如下

nghttp -ansy https://localhost/index.html

输出结果一般如下

[yufei@localhost htdocs]$ nghttp -ansy https://localhost/
***** Statistics *****

Request timing:
  responseEnd: the  time  when  last  byte of  response  was  received
               relative to connectEnd
 requestStart: the time  just before  first byte  of request  was sent
               relative  to connectEnd.   If  '*' is  shown, this  was
               pushed by server.
      process: responseEnd - requestStart
         code: HTTP status code
         size: number  of  bytes  received as  response  body  without
               inflation.
          URI: request URI

see http://www.w3.org/TR/resource-timing/#processing-model

sorted by 'complete'

id  responseEnd requestStart  process code size request path
  2    +28.44ms *    +4.88ms  23.56ms  200  56K /img1.jpg
 13    +29.75ms       +501us  29.25ms  200  255 /
  4    +44.22ms *    +4.92ms  39.30ms  200  53K /img2.jpg

输出结果中,带星号 ( * ) 标记的是服务器推送的资源

自动将资源推送到客户端

在某些情况下,使用 http2_push 指令在 NGINX 配置文件中列出希望推送的资源是不方便的,甚至是不可能的

出于这个原因,Nginx 还支持拦截 Link 预加载响应头的约定,然后推送这些响应头中标识的资源。

要启用预加载,需要在配置文件中添加 http2_push_preload 指令

server {
    # 确保服务器开启了 HTTP/2 支持        
    listen 443 ssl http2;

    ssl_certificate ssl/certificate.pem;
    ssl_certificate_key ssl/key.pem;

    root /var/www/html;

    # 拦截 Link 响应头部字段,然后和配置服务器推送
    location = /myapp {
        proxy_pass http://upstream;
        http2_push_preload on;
    }
}

例如,当 nginx 作为代理 ( 用于 HTTP,FastCGI 或其他流量类型 ) 运行时,上游服务器可以将这样的 Link 响应头添加到其响应中

Link: </img1.jpg>; as=image; rel=preload

nginx 会拦截此头部字段并开启服务器推送 img1.jptLink 响应头中的资源路径必须是绝对路径,不支持 ./img1.jpg 之类的相对路径。同时,路径中还可以添加一些查询字符串

如果要推送多个资源,可以添加 Link 响应头字段多次

Link: </img1.jpg>; as=image; rel=preload
Link: </img2.jpg>; as=image; rel=preload

更好的做法,是将这些资源放在一个 Link 头部中,并使用逗号分割

Link: </img1.jpg>; as=image; rel=preload,</img2.jpg>; as=image; rel=preload

如果不想要 nginx 推送某个预加载资源,可以,可以在 Link 头部字段中针对那个资源添加 nopush 参数,就像下面这样

Link: </img2.jpg>; as=image; rel=preload; nopush

当启用 http2_push_preload 后,我们还可以通过在 nginx 配置中设置响应头来启动预加载服务器推送

add_header Link "</img1.css>; as=image; rel=preload";

有选择地将资源推送给客户

显然的,HTTP/2 协议规范并没有确定,也没有推荐哪些资源是可推送的,哪些资源是不可推送的。因此,我们只能添加一些以前实践得来的经验

对于某些资源,如果我们知道客户端可能需要它们,但它们又不太可能已经被缓存,那么这些资源就是可推送的。

另一种可能的方式是仅在首次访问网站时将资源推送到客户端。例如,我们可以测试是否存在某个指定的会话 cookie,仅在会话 cookie 不存在时才预加载资源并有条件地设置 Link 响应头

假设客户端一直运作良好并且在后续的请求中都包含 cookie,则可以使用下面的 nginx 配置来确保每个浏览器会话期间内仅将资源推送到客户端一次

server {
    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 = /index.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=style; rel=preload";
}
目前尚无回复
简单教程 = 简单教程,简单编程
简单教程 是一个关于技术和学习的地方
现在注册
已注册用户请 登入
关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.