Maintenance: Server Push Support!
Recently, I took the time to add the official nginx ppa to my server to keep nginx up-to-date. In doing do, I jumped from a security-path-backported nginx 1.10 to version 1.14..... which adds a bunch of very cool new features. As soon as I leant that HTTP/2 Server Push was among the new features to be supported, I knew that I had to try it out.
In short, Server Push is a new technology - part of HTTP/2.0 (it's here at last :D) - that allows you to send resources to the client before they even know they need them. This is done by enabling it in the web server, and then having the web application append a specially-formatted link
header to outgoing requests - which tell the web server what resources it bundle along with the response.
First, let's enable it in nginx. This is really quite simple:
http {
# ....
http2_push_preload on;
# ....
}
This enables link
header parsing serve-wide. If you want to enable it for just a single virtual host, the http2_push_preload
directive can be placed inside server
blocks too.
With support enabled in nginx, we can add support to our web application (in my case, this website!). If you do a HEAD
request against a page on my website, you'll get a response looking like this:
HTTP/2 200
server: nginx/1.14.0
date: Tue, 21 Aug 2018 12:35:02 GMT
content-type: text/html; charset=UTF-8
vary: Accept-Encoding
x-powered-by: PHP/7.2.9-1+ubuntu16.04.1+deb.sury.org+1
link: </theme/core.min.css>; rel=preload; as=style, </theme/main.min.css>; rel=preload; as=style, </theme/comments.min.css>; rel=preload; as=style, </theme/bit.min.css>; rel=preload; as=style, </libraries/prism.min.css>; rel=preload; as=style, </theme/tagcloud.min.css>; rel=preload; as=style, </theme/openiconic/open-iconic.min.css>; rel=preload; as=style, </javascript/bit.min.js>; rel=preload; as=script, </javascript/accessibility.min.js>; rel=preload; as=script, </javascript/prism.min.js>; rel=preload; as=script, </javascript/smoothscroll.min.js>; rel=preload; as=script, </javascript/SnoozeSquad.min.js>; rel=preload; as=script
strict-transport-security: max-age=31536000;
x-xss-protection: 1; mode=block
x-frame-options: sameorigin
Particularly of note here is the link
header. it looks long and complicated, but that's just because I'm pushing multiple resources down. Let's pull it apart. In essence, the link
header takes a comma (,
) separated list of paths to resources that the web-server should push to the client, along with the type of each. For example, if https://bobsrockets.com/
wanted to push down the CSS stylesheet /theme/boosters.css
, they would include a link
header like this:
link: </theme/boosters.css>; rel=preload; as=style
It's also important to note here that pushing a resource doesn't mean that we don't have to utilise it somewhere in the page. By this I mean that pushing a stylesheet down as above still means that we need to add the appropriate <link />
element to put it to use:
<link rel="stylesheet" href="/theme/boosters.css" />
Scripts can be sent down too. Doing so is very similar:
link: </js/liftoff.js>; rel=preload; as=script
There are other as
values as well. You can send all kinds of things:
script
- Javascript filesstyle
- CSS Stylesheetsimage
- Imagesfont
- Fontsdocument
-<iframe />
contentaudio
- Sound files to be played via the HTML5<audio />
elementworker
- Web workersvideo
- Videos to be played via the HTML5<video />
element.
The full list can be found here. If you don't have support in your web server yet (or can't modify HTTP headers) for whatever reason, never fear! There's still something you can do. HTML also supports a similar <link rel="preload" href="...." />
element that you can add to your document's <head>
.
While this won't cause your server to bundle extra resources with a response, it'll still tell the client to go off and fetch the specified resources in the background with a high priority. Obviously, this won't help much with external stylesheets and scripts (since simply being present in the document is enough to get the client to request them), but it could still be useful if you're lazily loading images, for example.
In future projects, I'll certainly be looking out for opportunities to take advantage of HTTP/2.0 Server Push (probably starting with investigating options for Pepperminty Wiki). I've found the difference to be pretty extraordinary myself.
Of course, this is hardly the only feature that HTTP/2 brings. If there's the demand, I may blog about other features and how they work too.
Found this interesting? Confused about something? Using this yourself in a cool project? Comment below!