HTTPS NodeJS和Heroku。强制HTTPS?

时间:2014-07-08 23:46:38

标签: node.js ssl heroku https

我在Heroku上运行了一个NodeJS HTTP(非S)服务器。我已配置SSL,它接受HTTPS请求。我使用vanilla HTTP服务器的原因是the following

SSL termination occurs at Heroku's load balancers; they send your app plain (non-SSL) traffic, so your app should create a non-HTTPS server." 

不幸的是,我的应用程序仍然响应普通的HTTP请求。我想强制重定向或从HTTP到HTTPS。我可以用一些中间件来做到这一点:

/* At the top, with other redirect methods before other routes */
app.get('*',function(req,res,next){
  if(req.headers['x-forwarded-proto']!='https')
    res.redirect('https://mypreferreddomain.com'+req.url)
  else
    next() /* Continue to other routes if we're not redirecting */
})

但这是一个很好的解决方案吗? POST请求如何工作?如果我发布到HTTP,是否应该允许?

我想到的另一个最终方法是使用Nginx并在其中坚持从HTTP到HTTPS的重定向。不幸的是,Heroku不允许Nginx配置。

3 个答案:

答案 0 :(得分:1)

最好使用app.use(function(req, res, next{ /* ... */ });来捕获其他HTTP方法。

答案 1 :(得分:1)

因此,假设您将此放在中间件链的最前端,在路由器本身之前,这应该是非常高效的。

但是让我们把它提升一个档次。假设您在多个环境中部署此服务器,而不仅仅是Heroku,那么如果您希望协调多个环境的行为,那么您将很难避免在其中有条件地包含中间件或不断的条件分支。

如果你为Heroku编写一个特定的服务器,你可以跳过所有这些,类似的东西:

var app = require('./app').createApp();
var server = require('http').createServer(function (req, res) {
    if (!secure(req)) {
        // Redirect
        res.statusCode = 302;
        res.setHeader('Location', pathname);
        res.setHeader('Content-Length', '0');
        res.end();
    } else {
        app.handle(req, res);
    }
});
server.listen(80);

另外,尽量避免手动构建URL。您应该尝试使用URL库,特别是url.parse()url.resolve()函数,因为解析和构造URL非常重要(考虑隐式/显式尾部斜杠,哈希,查询和URL编码)。

这是一个小预览:

var url = require('url');

url.parse('http://www.foo.com?bar=baz#quux')
{ protocol: 'http:',
  slashes: true,
  auth: null,
  host: 'www.foo.com',
  port: null,
  hostname: 'www.foo.com',
  hash: '#quux',
  search: '?bar=baz',
  query: 'bar=baz',
  pathname: '/',
  path: '/?bar=baz',
  href: 'http://www.foo.com/?bar=baz#quux' }

答案 2 :(得分:0)

如果有人仍在寻找解决方案,请在您的NodeJ和Express JS文件中创建一个函数。

var enforceSsl = function (req, res, next) {
  if (req.headers['x-forwarded-proto'] !== 'https') {
    return res.redirect(['https://', req.get('Host'), req.url].join(''));
  }
  return next();
};

然后使用

应用中间件
app.use(enforceSsl);