Nodejs通过同一端口的HTTP和HTTPS

我一直在谷歌search,在这里看看在stackoverflow,但我找不到我喜欢的答案;-)

我有一个通过HTTPS和端口3001运行的NodeJS服务器。现在我想要获取端口3001上的所有传入HTTP请求,并通过HTTPS将它们redirect到相同的URL。

这一定是可能的。 不是吗?

谢谢!

如果遵循约定,则不需要在同一个端口上收听

按照惯例,当你请求http://127.0.0.1你的浏览器将尝试连接到端口80.如果您尝试打开https://127.0.0.1您的浏览器将尝试连接到端口443.所以为了保护所有的stream量只是传统的听HTTP端口80与redirect到HTTPS ,我们已经有一个HTTP端口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 

如果你必须听同一个端口

有没有简单的方法让HTTP / HTTPS在同一个端口上侦听。 最好的办法是在一个简单的networking套接字上创build代理服务器,该套接字根据传入连接的性质(http或https)pipe道(http或https)。

这里是完整的代码(基于https://gist.github.com/bnoordhuis/4740141 )完全是这样的。 它侦听本地主机:3000并将其pipe理到http(它又将其redirect到https),或者如果接收到的连接是https,它只是将它传递给https处理程序

 var fs = require('fs'); var net = require('net'); var http = require('http'); var https = require('https'); var baseAddress = 3000; var redirectAddress = 3001; var httpsAddress = 3002; var httpsOptions = { key: fs.readFileSync('./key.pem'), cert: fs.readFileSync('./cert.pem') }; net.createServer(tcpConnection).listen(baseAddress); http.createServer(httpConnection).listen(redirectAddress); https.createServer(httpsOptions, httpsConnection).listen(httpsAddress); function tcpConnection(conn) { conn.once('data', function (buf) { // A TLS handshake record starts with byte 22. var address = (buf[0] === 22) ? httpsAddress : redirectAddress; var proxy = net.createConnection(address, function () { proxy.write(buf); conn.pipe(proxy).pipe(conn); }); }); } function httpConnection(req, res) { var host = req.headers['host']; res.writeHead(301, { "Location": "https://" + host + req.url }); res.end(); } function httpsConnection(req, res) { res.writeHead(200, { 'Content-Length': '5' }); res.end('HTTPS'); } 

作为一个testing,如果你使用https连接你的https处理器:

 $ curl https://127.0.0.1:3000 -k HTTPS 

如果你用http连接它,你会得到redirect处理程序(只需要你到https处理程序):

 $ curl http://127.0.0.1:3000 -i HTTP/1.1 301 Moved Permanently Location: https://127.0.0.1:3000/ Date: Sat, 31 May 2014 16:36:56 GMT Connection: keep-alive Transfer-Encoding: chunked 

我知道它的一个老问题,但只是把它作为别人的参考。 我发现的最简单的方法是使用https://github.com/mscdex/httpolyglot模块。 似乎做得相当可靠

  var httpolyglot = require('httpolyglot'); var server = httpolyglot.createServer(options,function(req,res) { if (!req.socket.encrypted) { // Redirect to https res.writeHead(301, { "Location": "https://" + req.headers['host'] + req.url }); res.end(); } else { // The express app or any other compatible app app.apply(app,arguments); } }); // Some port server.listen(11000); 

如果通过单个端口提供HTTP和HTTPS是绝对的需求,则可以直接将请求代理到相关的HTTP实现,而不是将套接字pipe道连接到另一个端口。

httpx.js

 'use strict'; let net = require('net'); let http = require('http'); let https = require('https'); exports.createServer = (opts, handler) => { let server = net.createServer(socket => { socket.once('data', buffer => { // Pause the socket socket.pause(); // Determine if this is an HTTP(s) request let byte = buffer[0]; let protocol; if (byte === 22) { protocol = 'https'; } else if (32 < byte && byte < 127) { protocol = 'http'; } let proxy = server[protocol]; if (proxy) { // Push the buffer back onto the front of the data stream socket.unshift(buffer); // Emit the socket to the HTTP(s) server proxy.emit('connection', socket); } // Resume the socket data stream socket.resume(); }); }); server.http = http.createServer(handler); server.https = https.createServer(opts, handler); return server; }; 

如果它是纯粹的Node.JS HTTP模块,那么你可以试试这个:

 if (!request.connection.encrypted) { // Check if the request is not HTTPS response.writeHead(301, { // May be 302 Location: 'https://' + YourHostName + ':3001' + request.url /* Here you can add some more headers */ }); response.end(); // End the response } else { // Behavior for HTTPS requests }