Node.js 在Express/Node中通过https强制请求

Node.js 在Express/Node中通过https强制请求,node.js,express,Node.js,Express,我有一个Express.js(v2.5.8)(节点v0.6.12)服务器在端口3100上运行。它的前端是Nginx,它将http和https请求代理到端口3100 我想通过https强制某些URL。以下是一个示例(应用程序是我的Express服务器): ensureSec是我试图用来检查连接是否通过ssl的函数: function ensureSec(req, res, next) { if (req.session.ssl == true) { return next

我有一个Express.js(v2.5.8)(节点v0.6.12)服务器在端口3100上运行。它的前端是Nginx,它将http和https请求代理到端口3100

我想通过https强制某些URL。以下是一个示例(应用程序是我的Express服务器):

ensureSec是我试图用来检查连接是否通过ssl的函数:

function ensureSec(req, res, next) {
    if (req.session.ssl == true) { 
        return next(); 
    } else {
        req.session.ssl = true;
        res.redirect('https://' + url.parse(req.headers.referer).host +
        url.parse(req.url).pathname);
    }
}
重定向正常,但节点(在超时后)抛出一个错误,表示“无法获取/applyNow”


重定向到ssl的正确方法是什么?

您需要两个不同的express
app
对象来执行此操作。express服务器的每个实例一次只能侦听一个协议。这些都可以在一个node.js进程中完成,但您需要两个不同配置的express server
app
实例,一个用于http,另一个用于https。有关示例,请参见我的答案:

另见:

还要注意,您不应该分配
req.session.ssl
。将其设置为true并不会神奇地使客户端与TLS而不是明文HTTP连接。它是只读属性。分配它没有效果

还应注意,不能在单个端口上同时运行http和https。这就是http使用80和https使用443的原因


当您收到
无法获取/applyNow
错误时,这意味着您的express routes从未与请求路径匹配,因此您的
ensureSec
中间件从未被调用。

您可以在nginx服务器上配置ssl端口,并像其他请求一样将代理请求配置到node.js


无需更改node.js应用程序。只需在nginx上配置443端口,并向node.js应用程序发送证书和代理请求。

要补充Peter Lyons所说的,express要求您在一个端口上只运行一台服务器。如果您尝试在一个端口上运行两个http服务器,它将抛出EADDRINUSE错误

据我所知,您正在使用nginx协商SSL,并将http和https请求代理到您的Express应用程序。如果可能的话,我会选择在nginx中解决这个问题,但如果nginx不知道应该保护哪些路径(即仅通过https提供),或者出于其他原因,您希望在express app中这样做,以下是一些信息:

您应该从nginx获得
X-Forwarded-Proto
,仅当原始协议为https时才设置为
https
。以下是在nginx中执行此操作的方法:

proxy_set_header X-Forwarded-Proto https;
我还将转发
主机
标题:

proxy_set_header Host $http_host;
在您的express应用程序中,检查该项,或重定向到标题和请求路径中的主机(express将其解析为
req.path
,因此您不必):

如下所述:,使用Nginx,您可以利用“x-forwarded-proto”标头:


当您在前端使用Nginx时,实现这一点的最干净、最简单的方法是将Nginx中的http URL转发(重写)到HTTPS,而不是尝试在Express中重定向。这可以通过以下方式完成:

server {
  listen 12.34.56.78:80;
  server_name yourserver.com;

  location / {
      rewrite ^ https://$server_name$request_uri permanent;
  }
}
您可以使用以下行重写:

rewrite ^ https://ducklington.org$request_uri permanent;
只需设置您的位置以匹配您需要转发到https的路由或规则。

app.enable('trust proxy')

“在Varnish或Nginx等反向代理后面使用Express很简单,但它确实需要配置。通过app.enable('trust proxy')启用“trust proxy”设置,Express将知道它位于代理后面,并且X-Forwarded-*头字段可能是可信的,否则很容易被欺骗。”


我正在使用Nginx。Nginx可以处理http和https连接,因此我可以从我的应用程序中卸载它们。我只需要强制一些路径通过ssl运行。同样,您需要两个不同的端口和两个不同的express app实例。真正地这可以是一个node.js进程,您可以强制某些http路径重定向到https,但不能在同一端口上同时运行http和https等两种完全不同的协议。这不是node.js的限制,而是协议的设计。Peter,据我所知,Rob前面有一个nginx服务器,将请求代理到node.js服务器。因此,对于express应用程序,所有请求都是http。但是有些路径,Rob不希望express服务器处理,除非它是一个https请求(到nginx)。我建议改为在nginx中强制执行,这似乎简单得多。另外,我的理解是Rob使用
req.session.ssl
跟踪客户端是否通过https连接,这似乎不可靠(在正确的情况下需要重置)。啊,我误解了这个问题。谢谢,是的,会话值不可靠。谢谢。我已经这样做了。我只是想保护某些路径。我想在node应用程序中而不是nginx中这样做。这样做使部署更容易。X-Forwarded-Proto头文件实际上是一块隐藏的宝石。修好了,谢谢。
function ensureSec(req, res, next){
    if (req.headers["x-forwarded-proto"] === "https"){
       return next();
    }
    res.redirect("https://" + req.headers.host + req.url);  
});
server {
  listen 12.34.56.78:80;
  server_name yourserver.com;

  location / {
      rewrite ^ https://$server_name$request_uri permanent;
  }
}
rewrite ^ https://ducklington.org$request_uri permanent;