问题
New to Hapijs and trying to use it to create an app that uses HTTPS for all requests and redirect HTTP to the secure connection.The problem is the app goes in HTTPS mode no problem but if i change the URL to HTTP the server does not respond and don't know the reason why.
This is what i have came up with so far, it works but not for HTTP
var connectionOptions = {
port: 3000,
tls: {
key: fs.readFileSync(path.join(__dirname, 'key/key.pem'), 'utf8'),
cert: fs.readFileSync(path.join(__dirname, 'key/cert.pem'), 'utf8')
}
};
var server = new Hapi.Server();
server.connection(connectionOptions);
//This method not called when its HTTP
server.ext('onRequest', function (request, reply) {
if (request.headers['x-forwarded-proto'] === 'http') {
reply.redirect('https://' + request.headers.host +
request.url.path).code(301);
return reply.continue();
}
reply.continue();
});
var routes = require('./routes')(server);
server.route(routes);
if (!module.parent) {
server.start(function () {
console.log('Server running at:', server.info.uri);
});
}
How to force all request to be HTTPS. Thank you for the help
回答1:
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) {
...
}
});
回答2:
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
来源:https://stackoverflow.com/questions/28650829/hapijs-using-both-http-and-https-on-one-connection