我一直在尝试用我正在做的一个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.use(function(req,res,next) {
    if(req.headers["x-forwarded-proto"] == "http") {
        res.redirect("https://[your url goes here]" + req.url, next);
    } else {
        return next();
    } 
});

其他回答

从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报头

如果你的节点应用程序安装在IIS上,你可以在web.config中这样做

<configuration>
    <system.webServer>

        <!-- indicates that the hello.js file is a node.js application 
    to be handled by the iisnode module -->

        <handlers>
            <add name="iisnode" path="src/index.js" verb="*" modules="iisnode" />
        </handlers>

        <!-- use URL rewriting to redirect the entire branch of the URL namespace
    to hello.js node.js application; for example, the following URLs will 
    all be handled by hello.js:
    
        http://localhost/node/express/myapp/foo
        http://localhost/node/express/myapp/bar
        -->
        <rewrite>
            <rules>
                <rule name="HTTPS force" enabled="true" stopProcessing="true">
                    <match url="(.*)" />
                    <conditions>
                        <add input="{HTTPS}" pattern="^OFF$" />
                    </conditions>
                    <action type="Redirect" url="https://{HTTP_HOST}{REQUEST_URI}" redirectType="Permanent" />
                </rule>
                <rule name="sendToNode">
                    <match url="/*" />
                    <action type="Rewrite" url="src/index.js" />
                </rule>
            </rules>
        </rewrite>

        <security>
            <requestFiltering>
                <hiddenSegments>
                    <add segment="node_modules" />
                </hiddenSegments>
            </requestFiltering>
        </security>

    </system.webServer>
</configuration>

莱恩,谢谢你给我指明了方向。我用一些代码充实了你的答案(第二段),它是有效的。在这个场景中,这些代码片段被放在我的express应用程序中:

// set up plain http server
var http = express();

// set up a route to redirect http to https
http.get('*', function(req, res) {  
    res.redirect('https://' + req.headers.host + req.url);

    // Or, if you don't want to automatically detect the domain name from the request header, you can hard code it:
    // res.redirect('https://example.com' + req.url);
})

// have it listen on 8080
http.listen(8080);

https express服务器监听3000上的ATM。我设置了这些iptables规则,这样节点就不必以root用户运行:

iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j REDIRECT --to-port 3000

总的来说,这和我想要的完全一样。

为了防止通过HTTP窃取cookie,请参阅以下答案(来自评论)或使用以下代码:

const session = require('cookie-session');
app.use(
  session({
    secret: "some secret",
    httpOnly: true,  // Don't let browser javascript access cookies.
    secure: true, // Only use cookies over https.
  })
);

我找到了req。协议工作时,我使用express(没有测试,但我怀疑它工作)。使用当前节点0.10.22和express 3.4.3

app.use(function(req,res,next) {
  if (!/https/.test(req.protocol)){
     res.redirect("https://" + req.headers.host + req.url);
  } else {
     return next();
  } 
});