Nginx 的新特性 server push

简单来说就是有了 server push,服务器也有能力主动给客户端推送内容了。

传统的网页请求方式和有 server push 的请求方式对比

配置 server push

1.首先,我们看下未启用 server push 之前的请求,当请求网站根目录下的 /index.html 服务器会加载资源,如果 A 资源依赖 B, 则在去请求 B

2.开启 server push 需要 nginx 1.13.9 以上版本,在 server 段配置如下

要将资源与页面加载一起推送,请http2_push按如下所示使用该指令:

listen 443 ssl http2; # 需要开启 http2
……
 location / {
         http2_push /uploads/IMG_4224.JPG;
         http2_push /images/netease.png;
        }

验证HTTP / 2服务器推送

1.然后再次请求可以看到请求中会有 push 的字段,服务器开始先请求 /index.html 如果配置了 server push 则会直接把对应的资源一并返回给客户端。

2.也可以用 nghttp 测试,带*的表示是支持 server push 的

➜  ~ nghttp -ans https://awen.me
***** 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
 13    +31.14ms       +164us  30.97ms  200   9K /
 15    +88.43ms     +31.20ms  57.23ms  200  11K /css/main.css?v=5.1.1
 21    +88.50ms     +31.23ms  57.27ms  200   1K /js/src/utils.js?v=5.1.1
 23    +88.66ms     +31.23ms  57.43ms  200   1K /js/src/motion.js?v=5.1.1
 25    +88.70ms     +31.23ms  57.47ms  200 1017 /js/src/affix.js?v=5.1.1
 27    +88.71ms     +31.23ms  57.48ms  200  274 /js/src/schemes/pisces.js?v=5.1.1
 29    +89.84ms     +31.23ms  58.61ms  200   1K /js/src/scrollspy.js?v=5.1.1
 31    +89.89ms     +31.24ms  58.65ms  200  940 /js/src/post-details.js?v=5.1.1
 33    +89.90ms     +31.24ms  58.66ms  200  859 /js/src/bootstrap.js?v=5.1.1
 17    +91.21ms     +31.22ms  59.99ms  200   4K /favicon.ico?v=5.1.1
 19   +114.58ms     +31.23ms  83.35ms  200  26K /uploads/IMG_4224.JPG
 10   +224.05ms *   +24.51ms 199.54ms  200   4K /favicon.ico
 12   +224.12ms *   +24.52ms 199.60ms  404  162 /IMG_4224.JPG
 14   +224.22ms *   +24.53ms 199.69ms  200   2K /images/netease.png
  8   +313.28ms *   +24.50ms 288.78ms  200  47K /sitemap.xml
  2   +319.28ms *   +23.30ms 295.98ms  200 119K /rss.xml
  4   +431.86ms *   +24.48ms 407.38ms  200 129K /baidusitemap.xml
  6      +1.53s *   +24.49ms    1.50s  200   1M /search.xml

自动将资源推送给客户

在很多情况下,列出您希望推送到NGINX配置文件中的资源是不方便的,甚至是不可能的。出于这个原因,NGINX也支持拦截Link预加载头的约定,然后推送这些头中标识的资源。要启用预加载,请http2_push_preload在配置中包含指令:

server {
    # Ensure that HTTP/2 is enabled for the server        
    listen 443 ssl http2;

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

    root /var/www/html;

    # Intercept Link header and initiate requested Pushes
    location = /myapp {
        proxy_pass http://upstream;
        http2_push_preload on;
    }
}

例如,当NGINX作为代理服务器(用于HTTP,FastCGI或其他流量类型)运行时,上游服务器可以Link为其响应添加如下标题:

Link: </style.css>; as=style; rel=preload

NGINX拦截这个头并开始服务器推送/style.css。Link标题中的路径必须是绝对路径 - 不支持像./style.css这样的相对路径。该路径可以选择包含查询字符串。

要推送多个对象,可以提供多个Link标题,或者更好的是,将所有对象包含在逗号分隔的列表中:

Link: </style.css>; as=style; rel=preload, </favicon.ico>; as=image; rel=preload

如果您不希望NGINX推送预加载的资源,请将该nopush参数添加到标头中:

# Resource is not pushed
Link: </nginx.png>; as=image; rel=preload; nopush

当http2_push_preload启用时,您还可以通过在NGINX配置中设置响应标题来启动预加载服务器推送:

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

有选择地向客户推送资源

HTTP / 2规范没有解决确定是否推送资源的挑战。显然,如果你知道他们可能需要这些资源并且不太可能已经缓存了资源,那么最好只将资源推送给客户端。

一种可能的方法是仅在首次访问该网站时将资源推送给客户。例如,您可以测试会话cookie的存在情况,并Link有条件地设置标题,以便仅在会话cookie不存在时才预加载资源。

假设客户端运行良好,并在随后的请求中包含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 = /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=style; rel=preload";
}