An example of server push with HTTP/2 in node JS

Sibaprasad Maiti
Oct 29, 2018 · 5 min read
HTTP/2 with server push

What is HTTP/2 ?

HTTP/2 or HTTP/2.0 is the major version revision of the HTTP protocol used by World Wide Web. It’s predecessor is the SPDY protocol developed by Google. Today most of the browsers do support HTTP/2. You can check the compatibility of HTTP/2 in Can I Use. If you open your gmail in chrome browser, then that site is actually served over HTTP/2. Open the Developer Tools in chrome and go to Network tab. Reload the Gmail site. In the Protocol column you should see “h2”. (If you are not seeing the “Protocol” column then right click on any column header and select “Protocol” from the list ).

Advantages of HTTP/2

  • HTTP/2 is binary instead of textual because binary protocols are more efficient to parse, more compact on the wire and much less error prone.
  • HTTP/2 is fully multiplexed. That means multiple requests can be made on a single connection at the same time where as in HTTP/1.1 only one request can be outstanding on a connection at a time.
  • HTTP/2 is single connection only. Only one connection to the server is made to load a website and that connection remains open as long as the website is open in the browser. This reduces the number of handshaking operation overhead required to establish a TCP connection.
  • HTTP/2 uses header compression. Because many headers are sent with same values HTTP/2 uses HPACK header compression which reduces lot of overhead.
  • HTTP/2 allows the server to push resources to the client. Rather than client making requests for resources one by one and then server responding to those requests, server can proactively push resources to the client cache. Then client can drop the request for those resources. Which ensures less round trips on the wire.

Let’s implement HTTP/2

So, looks like HTTP/2 has significant performance improvement over HTTP/1.1. Let’s see how it works. We’ll implement this in Node JS.

The most recent versions of Node JS (version greater than v8.12.0) has the “http2” module for http/2 protocol support. We’ll have “experimental API” warning in the console when implemented this module. But that’s ok.

We’ll create an HTML page (index.html) which will have some additional dependencies like scripts, css, images etc. In Node JS we’ll create two servers — one normal HTTPS server and another is HTTP/2 server. When we go to the browser and enter the corresponding url to access our web server, then browser will receive the “index.html” file first. Upon parsing the html it will make requests for additional resources like scripts, css etc. But in our HTTP/2 implementation we’ll push all additional resources along with the “index.html” file. So browser will have those additional resources from the cache instead of making new requests to the server.

First create the index.html file —

In the head section of the html we have included a style.css, d3.js, jquery.js, react and react-dom, rxjs and three.js as additional resources (some random scripts). Also in the body we have included 9 images of Sir Tim Berners Lee. We will place all the scripts in the “scripts” folder and all images in the “images” folder.

Now let’s create the server in node JS. Since browsers only support HTTP/2 when encrypted, we need to create some certificates to setup a secure server. Also we need these certificate for our HTTPS server. We can use openssl for creating self signed certificates.

openssl req -x509 -newkey rsa:2048 -nodes -sha256 -subj '/CN=localhost' -keyout key.pem -out cert.pem

Copy the key.pem and cert.pem files and put under “secret” folder.

Now we will first create the normal HTTPS server.

const HTTPS_PORT = 3000;/**
* create a normal https server
*/
const https = require("https");
const fs = require("fs");
const mime = require("mime");
const serverOptions = {
key: fs.readFileSync(__dirname + "/secret/key.pem"),
cert: fs.readFileSync(__dirname + "/secret/cert.pem")
};
const httpsHandler = (req, res) => {
console.log(req.url);
// send empty response for favicon.ico
if (req.url === "/favicon.ico") {
res.writeHead(200);
res.end();
return;
}
const fileName =
req.url === "/" ? "index.html" : __dirname + req.url;
fs.readFile(fileName, (err, data) => {
if (err) {
res.writeHead(503);
res.end("Error occurred while reading file", fileName);
return;
}
res.writeHead(200, { "Content-Type": mime.getType(fileName) });
res.end(data);
});};https
.createServer(serverOptions, httpsHandler)
.listen(HTTPS_PORT, () =>
console.log("https server started on port", HTTPS_PORT)
);

Now we will create an HTTP2 secure server using node’s ‘http2’ module. This server will serve the index.html file when the request url is “/” and also push all files from the “scripts” directory and “images” directory and the style.css file.

Now run the node server and open up the browser. Open up the developer tool and go to Network tab. Go to the url https://localhost:3000. Normal https server is running on this port. (Since we are using self signed certificate to setup the TLS, chrome will show a warning. Get past that 😃). In the developer tool we will see that the browser has make requests for all files individually. Also in the console of our Node JS server we’ll see we have received requests for all additional resource files.

Now let’s go to https://localhost:3001. The HTTP/2 server is running on that port. Let’s check the Network tab again.

All other requests for script files and image files and stylesheet are received as “Push” from the server. If we check the console in the Node JS server then we will see only one request came this time that is for the url “/”.

Full code can be found here.

Sibaprasad Maiti

Written by

Full stack web developer, entrepreneur and Math lover.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade