HTTP/2 Server Push (with PHP and the Symfony HttpKernel)

HTTP/2 supports a feature called Server Push. This allows the server to send stylesheets, javascript and other assets to client browsers without separate requests.

Traditionally HTML documents contain references to various media, such as JavaScript, CSS and Images. A server application sends the document to the browser which interprets the document and starts downloading the referenced files from the server.

Your server application is likely aware of what resources are vital for the client. It can signal a Server Push enabled HTTP/2 server to send certain static files before the client even knows they are needed. This will lead to faster first paint times and swifter experiences altogether.

Server Push is a complementary technology and does not remove the need for linking stylesheets and other media in your documents. Your HTML source will continue to have the references, but the first response will contain extra headers to signal content that should be preloaded.

This method can replace the inlining of assets such as images and CSS into the HTML documents in a improved way, as the individual assets can be cached on the client. Clients that don't support Server Push will not act on these headers and will continue to function as they do today.

Server Push in PHP with the Symfony HttpKernel

The Symfony HttpKernel Component is widespread in Content Management Systems and other web applications built with PHP. It allows easy and structured construction of HTTP responses in an object oriented manner. Consider this Silex snippet used by a browser to render one image and next and previous buttons:

In the example the server will first send the JSON and the browser will then request individual images as they are needed. The client application could preload images 2.jpg and 3.jpg itself, but with slight modification we can make the server push them:

With a HTTP/2 Server Push compliant browser and server combination, the images will download before the client makes any request for them. This is accomplished by sending additional link headers that comply to the draft preload link specification from W3C. Note that the false parameter passed to the set method is used so multiple headers with the same identifier can be sent.

Most popular browsers now support HTTP/2 and server support is picking up too, with Apache mod_http2 and Nginx experimental support. You can also try use H2O to get started with HTTP/2 Server Push today with PHP.

Pushed assets are not currently visible in the network inspector of Blink based browsers such as Opera or Chrome, so the best way to see if your requests are going through is to tail the access log of your sever.

Note: Headers sent using vanilla PHP (or any other language) will function the same.

Not everything is important

Server Push can lead to greedy sending of excess data, defeating the optimisation effect. So it is always worth giving a second thought to whether certain assets should be pushed at all. Initiating a preload request on the client might be just as good, if not better, in many cases.

Wasting bandwidth by sending already cached items can be a challenge for server and browser vendors to implement. The H2O webserver, for example, implements a method called CASPer (cache-aware server-push) to overcome this:

When enabled, H2O maintains a fingerprint of the web browser cache, and cancels server-push suggested by the handlers if the client is known to be in possention of the content. The fingerprint is stored in a cookie named h2o_casper using Golomb-compressed sets (a compressed encoding of Bloom filter).

Just as with HTTP/1.1 optimisations such as domain sharding and other hacks to over come limitations, I'm sure we'll see inventive ways of (ab)using Server Push in the years to come.

Pushing initial JSON data for a clientside application is a viable alternative to Isomorphic Rendering for improving first-load performance of Single Page Applications built with Vue, Angular or React.

Written by Jani Tarvainen on Sunday October 4, 2015

Permalink - Tags: http2, serverpush, symfony