Dexecure performance engineering blog

How to create a zero dependency HTTP/2 static file server with Node.js (with examples)

Inian Parameshwaran
Inian Parameshwaran Oct 28, 2017
4 minutes read

HTTP/2 has been supported by the latest versions of the most popular browsers, including Google Chrome, Firefox, Safari and Microsoft Edge for quite sometime now. Websites delivered using HTTP/2 enjoys a wide range of new features including -

Node.js just launched support (v8.8.1) for HTTP/2 as part of their core. In this post, we will create a simple HTTP/2 server to serve static files and then demonstrate some cool features like HTTP/2 PUSH.

Step 0: Install Node.js v8.8.1

We will need at least Node.js v8.7.0 to be installed, you can download the latest version here.

Note - HTTP/2 is still considered as an experimental feature (Stability 0) even in the latest version of Node. It is not recommended to run production workloads using this yet, since the API might change. That being said, we will keep this blog post up to date as the API changes.

Step 1: Get an SSL certificate

Even though the HTTP/2 spec does not mandate HTTPS, browsers have decided that they will only support HTTP/2 on a HTTPS connection. This would also mitigate interference from older proxies which may not understand the newer protocol. If you already have HTTPS enabled, you can skip this step. Otherwise, you can generate a free certificate with letsencrypt if you want to try this out on a hosted domain. For your local server, a self-signed certificate will work. You can find how to setup a self-signed certificate here.

Step 2: Building a Static File server

Let us start with a simple server which just serves static files. Note that if you are using node.js 8.7.0, you need to run node with the --expose-http2 flag.

We will be listening to the stream event and responding to it with the corresponding file from the server root (public, in this case) using the respondWithFile API. We are using the mime-type module to look up the correct mime type to send along with the response.

Server Push Example

Now that we have a simple HTTP/2 server running, lets try to use one of the new features in HTTP/2 - HTTP/2 PUSH. This can lead to significant performance improvements in high latency environments, if done correctly.

We are loading a simple HTML file pointing to style.css which references to our font file. The request to the font file is only made after the CSS file is discovered in the HTML, downloaded and then parsed. This is how the waterfall would have usually looked like.

waterfall without http2

You can initiate a new PUSH with the pushStream API. Since we know that the browser is going to be requesting the font file in the future, we can PUSH the font file as soon as the server receives the request for the HTML file. When the actual request for the font file takes place, it is claimed from the PUSH cache, instead of making a network request then.

waterfall with http2

You can check out the full API for HTTP/2 in node.js here.

Using the compatibility API

Node.js also provides a compatibility layer to make it easier to get started with HTTP/2 on your existing web application.

You simply need to replace your existing https module with the new http2 module and things should work out of the box. For example, this is a simple HTTP/2 server written written with the HTTP1 version of the API. The same socket can answer to both HTTPS and HTTP/2 requests. Make sure you pass in the allowHTTP1 flag when creating the server. This would downgrade browsers which don’t support HTTP/2 back to a HTTP/1.1 connection.

It would still take time before full-blown frameworks like Express catch up to ensure that their API doesn’t break when used with HTTP/2, but with HTTP/2 server and client adoption catching up rapidly, we should get there soon!

Stay updated, because #perfmatters!

Start using a performance-first content delivery network now

First 14 days are free. No credit card is required. Cancel anytime.