Running Express, Koa and Hapi on HTTP/2

in Node.JS, HTTP2

Since I've started to work on web apps, I am searching for ways to improve page speeds and create better user experience. We are minifying our code, bundling files and optimizing images. One thing that we don't think about is server protocol. Is there a way to increase speed by changing protocol? Yes, there is! Welcome to HTTP/2 era!

HTTP/2 is latest version of HTTP protocol, made by the HTTP Working Group. It's developed from SPDY, experimental protocol made by Google. Last HTTP version is 1.1, released 1997, almost 20 years ago. Now's the time for a change!

HTTP/2 has many advantages. It uses single TCP protocol to server multiple files. It also compresses HTTP headers and sends them in binary format, which is better than HTTP/1 plain text format. There is also one amazing feature, HTTP/2 Server Push. It gives server ability to serve files before the client has requested them, which gives amazing speed improvements.

What about the support? Check it here: http://caniuse.com/#feat=http2. As you can see, the newer versions of browsers are supporting HTTP/2 protocol. In my opinion, I think that you can use HTTP/2 on your servers. I have tested HTTP/2 on various machines and only Internet Explorer had problems with it. People are moving to Edge so that also shouldn't be a problem in future.

Using HTTP/2 in Node

Now that we know what is HTTP/2 and are its advantages, we can start upgrading our Node apps. As you have probably seen, there is NPM module for almost anything. Developers have created two awesome modules for working with HTTP/2 protocol, http2 and spdy. They are using same API design as Node HTTPS API so it will be really simple to get started.

Generating SSL certificate

Let's write some code baby! We will implement HTTP/2 protocol on Express, Koa, and Hapi frameworks. But before we start, we need SSL certificate. HTTP/2 protocol only works on SSL and we need to generate certificate and key. I've already done it and you can use this certificate: https://github.com/IvanJov/node-on-http2/tree/master/certificate. If you still want to create your own, here is a simple tutorial (execute these commands in separate folder):

$ openssl genrsa -des3 -passout pass:x -out server.pass.key 2048
...
$ openssl rsa -passin pass:x -in server.pass.key -out server.key
writing RSA key
...
$ rm server.pass.key
$ openssl req -new -key server.key -out server.csr
...
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:California
...
A challenge password []:
...
$ openssl x509 -req -sha256 -days 365 -in server.csr -signkey server.key -out server.crt

After you generate certificate, you should see something like this: https://github.com/IvanJov/node-on-http2/tree/master/certificate

HTTP/2 in Express

We are starting with the most famous framework, Express. Let's assume that you already know how to setup express, init your project and create package.json. Next thing that we need to do is to install spdy package. I usually prefer to work with http2, but Express has some problems with it. They will hopefully be solved in next versions.

Let's install spdy:

npm install spdy --save

Now let's create index.js file and include packages in it, initialize our Express app and createa one route for testing:

const express = require('express');
const spdy = require('spdy');
const fs = require('fs');

const app = express();

app.get('/', function (req, res) {
  res.send('Serving using HTTP2!');
});

Next thing we need to do is to include our SSL certificate:

const options = {
  key: fs.readFileSync('path/to/server.key'),
  cert:  fs.readFileSync('path/to/server.crt')
};

And here comes the main part. Now we need to create spdy server, inject our app variable and listen on some port. Sounds easy? Look at this code:

spdy
  .createServer(options, app)
  .listen(3000, (err) => {
    if (err) {
      throw new Error(err);
    }

    console.log('Listening on port: ' + 3000 + '.');
  });

Now we have all parts of our app. If you inserted all parts of code, your index.js should look like this:

const express = require('express');
const spdy = require('spdy');
const fs = require('fs');

const app = express();

app.get('/', function (req, res) {
  res.send('Serving using HTTP2!');
});

const options = {
  key: fs.readFileSync('path/to/server.key'),
  cert:  fs.readFileSync('path/to/server.crt')
};

spdy
  .createServer(options, app)
  .listen(3000, (err) => {
    if (err) {
      throw new Error(err);
    }

    console.log('Listening on port: ' + 3000 + '.');
  });

Run your app

node index

and open https://localhost:3000

(if you see Your connection is not private page, just proceed localhost)

You should see this output:

Look at the protocol in the console. Yeah, it's HTTP/2, you've successfully implemented HTTP/2 protocol in your Express application!

HTTP/2 in Koa

Now that we know how to use HTTP/2 in Express, we can implement that in Koa too! Koa can use http2 so we will use it. Process will be almost same as setting up HTTP/2 in Express app.

Important Notice: This code works only with Koa v1!

After installing and setting up your Koa app, install http2 module:

npm install http2 --save

Then initialize Koa app with a test route:

const http2 = require('http2');
const koa = require('koa');
const _ = require('koa-route');
const fs = require('fs');

const app = koa();

app.use(_.get('/', function *(next) {
  this.body = 'Serving using HTTP2!';
  yield next;
}));

Now we can include our certificate, create http2server and inject our app variable:

const options = {
  key: fs.readFileSync('path/to/server.key'),
  cert:  fs.readFileSync('path/to/server.crt')
};

http2
  .createServer(options, app.callback())
  .listen(3000, (err) => {
    if (err) {
      throw new Error(err);
    }

    console.log('Listening on port: ' + 3000 + '.');
  });

We have created our http2 server and started to listen on port 3000. Let's run the app and see the output:

node index

Open https://localhost:3000/ and you should see this:

Yeah, it works!

HTTP/2 in Hapi

Last but not least, Hapi framework (my favorite). Setting up HTTP/2 in Hapi will also require http2 package.

After you install Hapi and setup package.json, let's install http2 package again (yeah, every time...):

npm install http2 --save

Now we need to setup our app in index.js. Hapi works a little bit different than Express and Koa, so now we won't need to setup http2 server and inject app, we will do the opposite, inject http2 server as listener in Hapi. We will also setup one simple route for testing. Check the code bellow:

const hapi = require('hapi');
const http2 = require('http2');
const fs = require('fs');

const options = {
  key: fs.readFileSync('path/to/server.key'),
  cert:  fs.readFileSync('path/to/server.crt')
};

const server = new hapi.Server();
server.connection({
  listener: http2.createServer(options),
  host: 'localhost',
  port: 3000,
  tls: true
});

server.route({
  method: 'GET',
  path:'/',
  handler: (req, res) => {

    return res('Serving using HTTP2!');
  }
});

server.start((err) => {
  if (err) {
    throw err;
  }
  console.log('Server running at:', server.info.uri);
});

Now we can run our app:

node index

and open https://localhost:3000/

The output is:

Woohoo, it works!

Summary

You've done it! Now you know how to use HTTP/w protocol in your Node applications. Everything you serve through your Express, Koa or Hapi application will be transferred much faster. If you use a web app to serve static files, it will be transferred in parallel and save so much time!

I have created a Github repo with all examples and instructions how to run the code: https://github.com/IvanJov/node-on-http2

I would like to hear your comments. Please let me know if everything is clear and if you maybe need some help. Thanks!

Comments