我一直在尝试用我正在做的一个node.js项目来设置HTTPS。我基本上遵循了这个例子的node.js文档:

// curl -k https://localhost:8000/
var https = require('https');
var fs = require('fs');

var options = {
  key: fs.readFileSync('test/fixtures/keys/agent2-key.pem'),
  cert: fs.readFileSync('test/fixtures/keys/agent2-cert.pem')
};

https.createServer(options, function (req, res) {
  res.writeHead(200);
  res.end("hello world\n");
}).listen(8000);

现在,当我做的时候

curl -k https://localhost:8000/

我得到

hello world

像预期的那样。但如果我这样做了

curl -k http://localhost:8000/

我得到

curl: (52) Empty reply from server

回想起来,这似乎是显而易见的,它将以这种方式工作,但与此同时,最终访问我的项目的人不会输入https://yadayada,我希望所有的流量从他们访问网站的那一刻起就使用https。

我怎么能得到节点(和Express,因为这是我正在使用的框架)把所有传入的流量交给https,不管它是否被指定?我还没有找到任何解决这个问题的文档。或者只是假设在生产环境中,节点在它前面有一些东西(例如nginx)来处理这种重定向?

这是我第一次尝试web开发,所以如果这是显而易见的,请原谅我的无知。


当前回答

这对我来说是有效的:

app.get("*",(req,res,next) => {
    if (req.headers["x-forwarded-proto"]) {
        res.redirect("https://" + req.headers.host + req.url)
    }
    if (!res.headersSent) {
        next()
    }
})

把它放在所有HTTP处理程序之前。

其他回答

这招对我很管用:

/* Headers */
require('./security/Headers/HeadersOptions').Headers(app);

/* Server */
const ssl = {
    key: fs.readFileSync('security/ssl/cert.key'),
    cert: fs.readFileSync('security/ssl/cert.pem')
};
//https server
https.createServer(ssl, app).listen(443, '192.168.1.2' && 443, '127.0.0.1');
//http server
app.listen(80, '192.168.1.2' && 80, '127.0.0.1');
app.use(function(req, res, next) {
    if(req.secure){
        next();
    }else{
        res.redirect('https://' + req.headers.host + req.url);
    }
});

建议在重定向到https之前添加头

现在,当你这样做时:

curl http://127.0.0.1 --include

你会得到:

HTTP/1.1 302 Found
//
Location: https://127.0.0.1/
Vary: Accept
Content-Type: text/plain; charset=utf-8
Content-Length: 40
Date: Thu, 04 Jul 2019 09:57:34 GMT
Connection: keep-alive

Found. Redirecting to https://127.0.0.1/

我使用快捷4.17.1

如果你遵循传统端口,因为HTTP默认尝试端口80,HTTPS默认尝试端口443,你可以简单地在同一台机器上有两个服务器: 代码如下:

var https = require('https');

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

https.createServer(options, function (req, res) {
    res.end('secure!');
}).listen(443);

// Redirect from http port 80 to https
var http = require('http');
http.createServer(function (req, res) {
    res.writeHead(301, { "Location": "https://" + req.headers['host'] + req.url });
    res.end();
}).listen(80);

使用https测试:

$ curl https://127.0.0.1 -k
secure!

与http:

$ curl http://127.0.0.1 -i
HTTP/1.1 301 Moved Permanently
Location: https://127.0.0.1/
Date: Sun, 01 Jun 2014 06:15:16 GMT
Connection: keep-alive
Transfer-Encoding: chunked

更多细节:Nodejs HTTP和HTTPS通过相同的端口

从0.4.12开始,我们还没有使用Node的HTTP/HTTPS服务器在同一个端口上监听HTTP和HTTPS的真正干净的方法。

有些人通过让Node的HTTPS服务器(这也适用于Express.js)侦听443(或其他端口),并让一个小型http服务器绑定到80并将用户重定向到安全端口来解决这个问题。

如果你必须能够在一个端口上处理这两个协议,那么你需要把nginx, lighttpd, apache,或其他一些web服务器放在那个端口上,并充当Node的反向代理。

如果你的应用程序在一个可信的代理(例如AWS ELB或正确配置的nginx)后面,这段代码应该工作:

app.enable('trust proxy');
app.use(function(req, res, next) {
    if (req.secure){
        return next();
    }
    res.redirect("https://" + req.headers.host + req.url);
});

注:

这假设您在80和443上托管站点,如果不是,则需要在重定向时更改端口 这还假定您正在终止代理上的SSL。如果你使用SSL端到端,请使用上面@basarat的答案。端到端SSL是更好的解决方案。 app.enable('trust proxy')允许express检查X-Forwarded-Proto报头

这对我来说是有效的:

app.get("*",(req,res,next) => {
    if (req.headers["x-forwarded-proto"]) {
        res.redirect("https://" + req.headers.host + req.url)
    }
    if (!res.headersSent) {
        next()
    }
})

把它放在所有HTTP处理程序之前。