node.js server and HTTP/2 (2.0) with express.js
If you are using express@^5
and http2@^3.3.4
, then the correct way to start the server is:
const http2 = require('http2');
const express = require('express');
const app = express();
// app.use('/', ..);
http2
.raw
.createServer(app)
.listen(8000, (err) => {
if (err) {
throw new Error(err);
}
/* eslint-disable no-console */
console.log('Listening on port: ' + argv.port + '.');
/* eslint-enable no-console */
});
Notice the https2.raw
. This is required if you want to accept TCP connections.
Note that at the time of this writing (2016 05 06), none of the major browsers support HTTP2 over TCP.
If you want to accept TCP and TLS connections, then you need to start the server using the default createServer
method:
const http2 = require('http2');
const express = require('express');
const fs = require('fs');
const app = express();
// app.use('/', ..);
http2
.createServer({
key: fs.readFileSync('./localhost.key'),
cert: fs.readFileSync('./localhost.crt')
}, app)
.listen(8000, (err) => {
if (err) {
throw new Error(err);
}
/* eslint-disable no-console */
console.log('Listening on port: ' + argv.port + '.');
/* eslint-enable no-console */
});
Note that at the time of this writing, I did manage to make express
and http2
to work (see https://github.com/molnarg/node-http2/issues/100#issuecomment-217417055). However, I have managed to get http2 (and SPDY) to work using spdy
package.
const spdy = require('spdy');
const express = require('express');
const path = require('path');
const fs = require('fs');
const app = express();
app.get('/', (req, res) => {
res.json({foo: 'test'});
});
spdy
.createServer({
key: fs.readFileSync(path.resolve(__dirname, './localhost.key')),
cert: fs.readFileSync(path.resolve(__dirname, './localhost.crt'))
}, app)
.listen(8000, (err) => {
if (err) {
throw new Error(err);
}
/* eslint-disable no-console */
console.log('Listening on port: ' + argv.port + '.');
/* eslint-enable no-console */
});
There is an open pr for express 5.0 since 2018, https://github.com/expressjs/express/pull/3730. Until that is merged, it won't work out of the box.
I have created the solution in the form of a package, https://www.npmjs.com/package/http2-express-bridge
const express = require('express')
const http2Express = require('http2-express-bridge')
const http2 = require('http2')
const { readFileSync } = require('fs')
// Use the wrapper function that returns the application
const app = http2Express(express)
const options = {
key: readFileSync('<Certificate Key>'),
cert: readFileSync('<Certificate file>'),
allowHTTP1: true
};
app.get('/', function (req, res) {
res.send('Hello World')
})
const server = http2.createSecureServer(options, app)
server.listen(3000, () => {
console.log(`listening on port 3000`)
})
This works, and it falls back to Http/1.1 when it receives an Http/1.1 request.
I have also included 'res.push' method for ease of server push. The package works with ESModules and Typescript.
var express = require('express');
var app = express();
app.get('/', function (req, res) {
res.send('hello, http2!');
});
var options = {
key: fs.readFileSync('./example/localhost.key'),
cert: fs.readFileSync('./example/localhost.crt')
};
require('http2').createServer(options, app).listen(8080);
EDIT
This code snippet was taken from a conversation on Github.