Hapijs using both Http and Https on one connection

大憨熊 提交于 2019-12-03 08:50:35

You can't use http and https on the same connection. Behind the scenes Hapi will create a Node http server or an https server depending on your tls config, as shown in this line from lib/connection.js:

this.listener = this.settings.listener || (this.settings.tls ? Https.createServer(this.settings.tls) : Http.createServer());

You should create another connection to your server that doesn't use TLS and then redirect non-TLS requests to the https url.

EXAMPLE

const Hapi = require('hapi');
const Fs = require('fs');
const Url = require('url');

const config = {
    host: 'localhost',
    http: { port: 3001 },
    https: {
        port: 3000,
        key: Fs.readFileSync('key.key'),
        cert: Fs.readFileSync('cert.pem')
    }
}

const server = new Hapi.Server();

// https connection

server.connection({
    port: config.https.port,
    tls: {
        key: config.https.key,
        cert: config.https.cert
    }
});

// http connection

server.connection({ port: config.http.port });

server.route({
    method: 'GET',
    path: '/',
    handler: function (request, reply) {

        reply('Hello world');
    }
});

server.ext('onRequest', (request, reply) => {

    if (request.connection.info.port !== config.https.port) {

        return reply.redirect(Url.format({
            protocol: 'https',
            hostname: request.info.hostname,
            pathname: request.url.path,
            port: config.https.port
        }));
    }

    return reply.continue();
});

server.start((err) => {

    if (err) {
        throw err;
    }

    console.log('Started server');
});

EDIT

If you're allowing insecure connections to your server before redirecting to HTTPS, consider also employing HTTP Strict Transport Security (HSTS) to prevent MITM attacks. You can set HSTS headers using the route config security option:

server.route({
    config: {
        security: {
            hsts: {
                maxAge: 15768000,
                includeSubDomains: true,
                preload: true
            }
        }
    },
    method: 'GET',
    path: '/',
    handler: function (request, reply) {

        ...
    }
});

Another solution that justs reroutes every http call, no checks on every request. You must use 2 connections though.

// create the 2 connections and give the http one a specific label e.g. http
// apply the http catch all route to only the http connection
// I make use of connection label to make sure I only register the catch all route on the http connection
server.select('http').route({
    method: '*',
    path: '/{p*}',
    handler: function (request, reply) {

        // redirect all http traffic to https
        // credit to Matt for the URL.format
        return reply.redirect(Url.format({
            protocol: 'https',
            hostname: request.info.hostname,
            pathname: request.url.path,
            port: config.https.port
        })).permanent();
    },
    config: {
        description: 'Http catch route. Will redirect every http call to https'
    }
});

For more info on the redirect see the docs

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!