Node.JS、Express和Heroku-如何处理HTTP和HTTPS?

9
我有一个应用程序,这是一个普通的Express应用程序 - 简单的服务器逻辑、视图和大量客户端JS。我需要进行许多AJAX请求中的一些必须由HTTPS协议保护(有些则不需要)。
因此,我的服务器应该既可以使用HTTP也可以使用HTTPS。它还应该在本地机器上(通常使用nodemon运行)以及在Heroku上正常工作。
据我了解,Heroku只提供一个端口(process.env.PORT),您可以监听此端口,并通过代理处理所有请求(因此,您的应用程序正在监听此端口,而不会受到协议的影响 - 对吗?)
所以,我的理解是 - 我应该为开发机器和Heroku编写一些不同的代码?
例如:
...
app = express()
...

if process.env.NODE_ENV == 'production'
  app.listen(process.env.PORT)
else
  https = require('https')
  http = require('http')
  http.createServer(app).listen(5080) # some local port
  options = {
    key: fs.readFileSync('key.pem'), 
    cert: fs.readFileSync('cert.pem') # my self-signed files
  }
  https.createServer(options, app).listen(5443) # some different local port

这是处理此事的适当方式吗?

3个回答

12

对于Coffeescript-challenges,这是Guard的答案转换为Javascript的版本。我采取了一种不同的方法来拆分if else语句。

var express = require('express');
var http = require('http');
var https = require('https');
var fs = require('fs');
var privateKey = fs.readFileSync('./config/localhost.key').toString();
var certificate = fs.readFileSync('./config/localhost.crt').toString();

var options = {
  key : privateKey
, cert : certificate
}

var app = express();

// Start server.
var port = process.env.PORT || 3000; // Used by Heroku and http on localhost
process.env['PORT'] = process.env.PORT || 4000; // Used by https on localhost

http.createServer(app).listen(port, function () {
    console.log("Express server listening on port %d in %s mode", this.address().port, app.settings.env);
});

// Run separate https server if on localhost
if (process.env.NODE_ENV != 'production') {
    https.createServer(options, app).listen(process.env.PORT, function () {
        console.log("Express server listening with https on port %d in %s mode", this.address().port, app.settings.env);
    });
};

if (process.env.NODE_ENV == 'production') {
    app.use(function (req, res, next) {
        res.setHeader('Strict-Transport-Security', 'max-age=8640000; includeSubDomains');
        if (req.headers['x-forwarded-proto'] && req.headers['x-forwarded-proto'] === "http") {
            return res.redirect(301, 'https://' + req.host + req.url);
        } else {
            return next();
            }
    });
} else {
    app.use(function (req, res, next) {
        res.setHeader('Strict-Transport-Security', 'max-age=8640000; includeSubDomains');
        if (!req.secure) {
            return res.redirect(301, 'https://' + req.host  + ":" + process.env.PORT + req.url);
        } else {
            return next();
            }
    });

};

8

嗯,最近社区似乎相当冷清(希望我错了)

回答是:

a)是的,这是处理它的方法

b)检查是否处于安全模式的方法也取决于环境:

if process.env.NODE_ENV == 'production'
  is_secure = (req) ->
    req.headers['x-forwarded-proto'] == 'https'
else
  is_secure = (req) -> req.secure

添加 如果您希望强制使用 HTTPS:

redirect_to_https = (req, res, next) ->
  if not is_secure(req)
    res.redirect config.SECURE_DOMAIN + req.url
  else
    next()

app
  .use(redirect_to_https)

一个快速的问题 - 我们能否像这样获取主机 return res.redirect('https://' + req.headers.host + req.url); 而不是从配置中获取? - Pavel Nikolov
可能是的,但是为了消除冗余而已吗?你可以从浏览器中获取标题。从配置(或环境变量)中获取重要值对我来说似乎是更可靠的选择。 - Guard

3
您可以使用app.enable('trust proxy'),然后req.secure布尔值(http/https)也适用于Heroku或任何兼容的SSL终止代理。

2
在 Express 4 中,可以使用 app.set('trust proxy', 'loopback');。更多详情请参见 http://expressjs.com/4x/api.html#app-settings。 - Arvind Sridharan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接