node-http2: Doesn't work with Express.js

I wrote simple Express app and got an error.

var fs = require('fs');
var express = require('express');
var app = express();

app.get('/', function (req, res) {
  res.send('hello!')
})

var options = {
  key: fs.readFileSync('./ssl/key.pem'),
  cert: fs.readFileSync('./ssl/cert.pem')
};

require('http2').createServer(options, app).listen(8080);
// require('https').createServer(options, app).listen(8080);// https module works well
_stream_readable.js:505
    dest.end();
         ^
TypeError: undefined is not a function
    at Stream.onend (_stream_readable.js:505:10)
    at Stream.g (events.js:199:16)
    at Stream.emit (events.js:129:20)
    at _stream_readable.js:908:16
    at process._tickCallback (node.js:355:11)

Is that a node-http2’s matter or Node’s one? It is hard to debug for me…

Node: v0.12.0 node-http2: v3.2.0 express: v4.11.2

About this issue

  • Original URL
  • State: open
  • Created 9 years ago
  • Comments: 43 (10 by maintainers)

Most upvoted comments

@gajus could you put that big log code block into a gist at all? It is making the page very large.

Using:

"express": "^5.0.0-alpha.2",
"http2": "^3.3.4",
const http2 = require('http2');
const express = require('express');
const yargs = require('yargs');
const path = require('path');
const fs = require('fs');

const argv = yargs
      .help()
    .strict()
    .options({
        port: {
            default: 8000,
            demand: true,
            type: 'number'
        }
    })
    .argv;

process.on('unhandledRejection', (reason, promise) => {
    /* eslint-disable no-console */
    console.log('Unhandled RejectionPromise');
    console.log('promise', promise);
    console.log('reason', reason);
    console.log('reason.stack', reason.stack);
    /* eslint-enable */
});

const app = express();


app.get('/', (req, res) => {
    res.json({foo: 'test'});
});

/* eslint-disable no-console, no-unused-vars */
app.use((err, req, res, next) => {
    console.error(err.stack);
    /* eslint-enable */

    res
        .status(500)
        .send('Internal Server Error');
});

http2
    .createServer({
        log: require('bunyan').createLogger({name: 'myapp'}),
        key: fs.readFileSync(path.resolve(__dirname, './localhost.key')),
        cert: fs.readFileSync(path.resolve(__dirname, './localhost.crt'))
    }, app)
    .listen(argv.port, (err) => {
        if (err) {
            throw new Error(err);
        }

        /* eslint-disable no-console */
        console.log('Listening on port: ' + argv.port + '.');
        /* eslint-enable no-console */
    });

Does not work.

The complete log output: https://gist.github.com/gajus/843fd2d682f946680af161b7054b01f2

@azat-co SPDY is dead

@gajus please hide you code

For now (while we are waiting for Express v5) you can use spdy with express

const port = 3000
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'})
})
let options = {
    key: fs.readFileSync(__dirname + '/server.key'),
    cert:  fs.readFileSync(__dirname + '/server.crt')
};
console.log(options);
spdy
  .createServer(options, app)
  .listen(port, (err) => {
      if (err) {
          process.exit(1)
      }
      console.log('Listening on port: ' + port + '.')
  })

whats up with babel.js in there?

@azat-co Google Chrome doesn’t support SPDY anymore: http://blog.chromium.org/2016/02/transitioning-from-spdy-to-http2.html

So when even its inventor won’t support it you know it is dead

So if the only reason why http2 doesn’t work with Express is because of this prototype stuff, then it should be fixed in 5.0 this summer.

If we are brainstorming on a method to get it into 4.x and also keep backwards compatibility, then we can and a PR would be welcome 😃 Some things to think of is that with sub apps, we don’t know the prototype we want to replace, so you would need to walk down the entire chain searching for IncomingRequest. We also need to think about how to handle things like non-configurable properties, where today there is no issue and Express will overwrite them, but changing to a non-proto-replacement may cause different behavior or errors for people.

In Express 5 we are moving to prototype injection over replacement, though it’s not backwards compatible.