我一直在尝试使用我正在开发的node.js项目设置HTTPS。对于这个例子,我基本上遵循了node.js documentation:
// 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。
如何将所有传入的流量传递给https的节点(以及我正在使用的Express),无论是否指定了它?我找不到任何解决此问题的文档。或者只是假设在生产环境中,节点有一些位于它前面的东西(例如nginx)来处理这种重定向?
这是我第一次涉足网络开发,所以请原谅我的无知,如果这是显而易见的事情。
答案 0 :(得分:148)
// set up plain http server
var http = express.createServer();
// 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
总之,这完全符合我的要求。
答案 1 :(得分:104)
如果您遵循传统端口,因为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
答案 2 :(得分:55)
感谢这个家伙: https://www.tonyerwin.com/2014/09/redirecting-http-to-https-with-nodejs.html
app.use (function (req, res, next) {
if (req.secure) {
// request was via https, so do no special handling
next();
} else {
// request was via http, so redirect to https
res.redirect('https://' + req.headers.host + req.url);
}
});
答案 3 :(得分:21)
使用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);
}
答案 4 :(得分:12)
从0.4.12开始,我们没有真正干净的方式来监听HTTP&使用Node的HTTP / HTTPS服务器在同一端口上使用HTTPS。
有些人通过拥有Node的HTTPS服务器(这也适用于Express.js)来解决这个问题,请听443(或其他一些端口)并且还有一个小的http服务器绑定到80并将用户重定向到安全港口。
如果您必须能够在单个端口上处理这两种协议,那么您需要在该端口上放置nginx,lighttpd,apache或其他一些Web服务器,并充当Node的反向代理。
答案 5 :(得分:8)
需要更新此答案才能使用Express 4.0。以下是我如何使用单独的http服务器:
var express = require('express');
var http = require('http');
var https = require('https');
// Primary https app
var app = express()
var port = process.env.PORT || 3000;
app.set('env', 'development');
app.set('port', port);
var router = express.Router();
app.use('/', router);
// ... other routes here
var certOpts = {
key: '/path/to/key.pem',
cert: '/path/to/cert.pem'
};
var server = https.createServer(certOpts, app);
server.listen(port, function(){
console.log('Express server listening to port '+port);
});
// Secondary http app
var httpApp = express();
var httpRouter = express.Router();
httpApp.use('*', httpRouter);
httpRouter.get('*', function(req, res){
var host = req.get('Host');
// replace the port in the host
host = host.replace(/:\d+$/, ":"+app.get('port'));
// determine the redirect destination
var destination = ['https://', host, req.url].join('');
return res.redirect(destination);
});
var httpServer = http.createServer(httpApp);
httpServer.listen(8080);
答案 6 :(得分:6)
我发现当我使用快递时,req.protocol有效(没有测试,但我怀疑它有效)。使用当前节点0.10.22和快速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();
}
});
答案 7 :(得分:5)
如果您的应用程序位于受信任的代理(例如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);
});
注意:
答案 8 :(得分:4)
这里的大多数答案建议使用req.headers.host标头。
HTTP 1.1需要Host头,但它实际上是可选的,因为HTTP客户端实际上可能不会发送头,而node / express将接受此请求。
您可能会问:哪个HTTP客户端(例如:浏览器)可以发送缺少该标头的请求? HTTP协议非常简单。您可以在几行代码中创建HTTP请求,不发送主机头,如果每次收到格式错误的请求,都会抛出异常,并且根据您处理此类异常的方式,这可能会导致服务器关闭。 / p>
所以始终验证所有输入。这不是偏执狂,我收到的服务中缺少主机头的请求。
此外,从不将网址视为字符串。使用节点url模块修改字符串的特定部分。将URL作为字符串处理可以在许多方面被利用。不要这样做。
答案 9 :(得分:4)
您可以使用express-force-https模块:
npm install --save express-force-https
var express = require('express');
var secure = require('express-force-https');
var app = express();
app.use(secure);
答案 10 :(得分:3)
var express = require('express');
var app = express();
app.get('*',function (req, res) {
res.redirect('https://<domain>' + req.url);
});
app.listen(80);
这是我们使用的,效果很好!
答案 11 :(得分:3)
你可以使用“net”模块来监听HTTP&amp;同一端口上的HTTPS
var https = require('https');
var http = require('http');
var fs = require('fs');
var net=require('net');
var handle=net.createServer().listen(8000)
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(handle);
http.createServer(function(req,res){
res.writeHead(200);
res.end("hello world\n");
}).listen(handle)
答案 12 :(得分:3)
我使用Basarat提出的解决方案,但我还需要覆盖端口,因为我曾经有两个不同的端口用于HTTP和HTTPS协议。
res.writeHead(301, { "Location": "https://" + req.headers['host'].replace(http_port,https_port) + req.url });
我更喜欢使用非标准端口,因此在没有root权限的情况下启动nodejs。 我喜欢8080和8443因为我来自tomcat的多年编程。
我的完整档案
var fs = require('fs');
var http = require('http');
var http_port = process.env.PORT || 8080;
var app = require('express')();
// HTTPS definitions
var https = require('https');
var https_port = process.env.PORT_HTTPS || 8443;
var options = {
key : fs.readFileSync('server.key'),
cert : fs.readFileSync('server.crt')
};
app.get('/', function (req, res) {
res.send('Hello World!');
});
https.createServer(options, app).listen(https_port, function () {
console.log('Magic happens on port ' + https_port);
});
// Redirect from http port to https
http.createServer(function (req, res) {
res.writeHead(301, { "Location": "https://" + req.headers['host'].replace(http_port,https_port) + req.url });
console.log("http request, will go to >> ");
console.log("https://" + req.headers['host'].replace(http_port,https_port) + req.url );
res.end();
}).listen(http_port);
然后我使用iptable在我的HTTP和HTTPS端口上转发80和443流量。
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j REDIRECT --to-port 8443
答案 13 :(得分:2)
这对我有用:
.put("request.headers.X-Found-Cluster", clusterName)
答案 14 :(得分:2)
此脚本在加载页面时保存 URL 页面并检查地址是 https 还是 http。如果是http,脚本会自动将你重定向到同一个https页面
(function(){
var link = window.location.href;
if(link[4] != "s"){
var clink = "";
for (let i = 4; i < link.length; i++) {
clink += link[i];
}
window.location.href = "https" + clink;
}
})();
答案 15 :(得分:1)
您可以实例化2个Node.js服务器 - 一个用于HTTP和HTTPS
您还可以定义两个服务器都将执行的设置功能,这样您就不必编写大量重复的代码。
这就是我做的方式:(使用restify.js,但也适用于express.js或节点本身)
http://qugstart.com/blog/node-js/node-js-restify-server-with-both-http-and-https/
答案 16 :(得分:0)
这对我有用:
/* 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/
我使用Express 4.17.1
答案 17 :(得分:0)
如果您的节点应用程序安装在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>
答案 18 :(得分:0)
关于杰克答案的更新代码。在您的https服务器旁边运行它。
// set up plain http server
var express = require('express');
var app = express();
var http = require('http');
var server = http.createServer(app);
// set up a route to redirect http to https
app.get('*', function(req, res) {
res.redirect('https://' + req.headers.host + req.url);
})
// have it listen on 80
server.listen(80);
答案 19 :(得分:0)
这对我来说适用于快递:
app.get("*",(req,res,next) => {
if (req.headers["x-forwarded-proto"]) {
res.redirect("https://" + req.headers.host + req.url)
}
if (!res.headersSent) {
next()
}
})
将其放在所有HTTP处理程序之前。
答案 20 :(得分:0)
这个想法是检查传入的请求是否是使用 https 发出的,如果是,则不要再次将其重定向到 https,而是照常继续。否则,如果它是 http,则通过附加 https 重定向它。
app.use (function (req, res, next) {
if (req.secure) {
next();
} else {
res.redirect('https://' + req.headers.host + req.url);
}
});