Nginx 1.13.9+ HTTP/2 server push

Nginx has recently implemented HTTP/2 server push. This feature allows Nginx to push content to frontend browser without/before the browser requesting for the content. 

In usual page loading, the browser will be repeating GET > RECEIVE > GET > RECEIVE > GET > RECEIVE. With HTTP/2 server push, it reduces GET for all the push contents, which results in a sequence similar to GET > RECEIVE > RECEIVE PUSH > RECEIVE PUSH > GET > RECEIVE. This feature will actually improve the loading time because Round Trip Time (RTT) is reduced.

Steps to enable this feature:

(1) Install Nginx v1.13.9 or later. (At this time, this version is in the mainline repository)

(2) There are 2 ways to enable this feature.

(a) Static way - By specifying the content to push in your http block.

server {

  location = / {
      http2_push /main.css;
  }
  
}

(b) Dynamic way - By asking Nginx to intercept response and check for a specific header.

server {

  location = / {
      http2_push_preload on;
  }
  
}

When this is set, Nginx will intercept "Link" header. You can specify the content to push in this header. E.g.

Link "</main.css>; as=style; rel=preload"
Link "</main.js>; as=script; rel=preload"
Link "</background.jpg>; as=image; rel=preload"

These headers can be set in upstream server or directly from your application.

(3) Make sure your have enabled http2 feature.

server {
    listen 443 ssl http2;

}

(4) Reload Nginx and test.

(5) You can observe the push behavior via chrome://net-internals/#events

t=7272 [st= 1]  HTTP2_SESSION_RECV_PUSH_PROMISE
                --> :method: GET
                    :path: /main.css
                    :scheme: https
                    :authority: 192.168.x.x
                    accept-encoding: gzip, deflate, br
                    accept-language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7,ms;q=0.6,zh-TW;q=0.5
                    user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36
                --> id = 31
                --> promised_stream_id = 18
t=7272 [st= 1]  HTTP2_STREAM_SEND_PRIORITY
                --> exclusive = true
                --> parent_stream_id = 31
                --> stream_id = 18
                --> weight = 110

(6) If the push content is already loaded or is cached, client will reject the push hint. You will see something like this:

t=  4235 [st=     1]  HTTP2_SESSION_RECV_PUSH_PROMISE
                      --> :method: GET
                          :path: /main.css
                          :scheme: https
                          :authority: 192.168.x.x
                          accept-encoding: gzip, deflate, br
                          accept-language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7,ms;q=0.6,zh-TW;q=0.5
                          user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36
                      --> id = 25
                      --> promised_stream_id = 14
t=  4235 [st=     1]  HTTP2_SESSION_SEND_RST_STREAM
                      --> description = "Duplicate pushed stream with url: https://192.168.x.x/main.css"
                      --> error_code = "7 (REFUSED_STREAM)"
                      --> stream_id = 14

Note 1: This feature is available in Nginx current mainline 1.13.9+. Which means that it is not yet supported by custom build such as Passenger version of Nginx.

Note 2: Supported browser can be found here: https://caniuse.com/#feat=http2


AI Summary
Chrome On-device AI 2024-07-27 11:20:13

Share Article