Hapijs的新用户并尝试使用它来创建一个应用程序,该应用程序对所有请求使用HTTPS并将HTTP重定向到安全连接。问题是应用程序进入HTTPS模式没有问题,但如果我更改URL对HTTP服务器没有响应,也不知道原因。
这是我到目前为止所提出的,它可以工作但不适用于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);
});
}
如何强制所有请求为HTTPS。 谢谢你的帮助
答案 0 :(得分:14)
您无法在同一连接上使用http和https。在幕后Hapi将创建一个节点http
服务器或一个https
服务器,具体取决于您的tls
配置,如lib/connection.js
中的此行所示:
this.listener = this.settings.listener || (this.settings.tls ? Https.createServer(this.settings.tls) : Http.createServer());
您应该创建与服务器的另一个连接,该连接不使用TLS,然后将非TLS请求重定向到https网址。
示例强>
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');
});
修改强>
如果您在重定向到HTTPS之前允许与服务器进行不安全的连接,请考虑使用HTTP Strict Transport Security (HSTS)来阻止MITM攻击。您可以使用route config security
选项设置HSTS标头:
server.route({
config: {
security: {
hsts: {
maxAge: 15768000,
includeSubDomains: true,
preload: true
}
}
},
method: 'GET',
path: '/',
handler: function (request, reply) {
...
}
});
答案 1 :(得分:5)
另一种解决方案,即重新路由每个http调用,不检查每个请求。 你必须使用2个连接。
// 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'
}
});
有关重定向的详细信息,请参阅the docs