Nodejs HTTP e HTTPS sulla stessa porta

Ho cercato su google e guardando qui stackoverflow, ma non riesco a trovare una risposta che mi piace 😉

Ho un server NodeJS che funziona su HTTPS e sulla porta 3001. Ora mi piacerebbe recuperare tutte le richieste HTTP in arrivo sulla porta 3001 e reindirizzarle sullo stesso URL ma su HTTPS.

Questo deve essere ansible. Non è vero?

Grazie!

Non è necessario ascoltare sulla stessa porta se si seguono le convenzioni

Per convenzione quando richiedi http://127.0.0.1 tuo browser proverà a connettersi alla porta 80. Se provi ad aprire https://127.0.0.1 tuo browser proverà a connettersi alla porta 443. Quindi per proteggere tutto il traffico è semplicemente convenzionale ascoltare la porta 80 su http con un reindirizzamento a https in cui abbiamo già un listener per https per la porta 443. Ecco il codice:

 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); 

Prova con https:

 $ curl https://127.0.0.1 -k secure! 

Con 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 

Se devi ascoltare sulla stessa porta

Non c’è un modo semplice per ascoltare http / https sulla stessa porta. La soluzione migliore è creare un server proxy su un semplice socket di rete che rimandi a (http o https) in base alla natura della connessione in entrata (http vs. https).

Ecco il codice completo (basato su https://gist.github.com/bnoordhuis/4740141 ) che fa esattamente questo. Ascolta su localhost: 3000 e lo invia a http (che a sua volta lo reindirizza a https) o se la connessione in entrata è in https, la passa semplicemente a https handler

 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'); } 

Come test, se lo colleghi con https ottieni il gestore https:

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

se lo colleghi con http ottieni il gestore di reindirizzamento (che ti porta semplicemente al gestore di 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 

So che è una vecchia domanda, ma la metto solo come riferimento per qualcun altro. Il modo più semplice che ho trovato è stato utilizzare il modulo https://github.com/mscdex/httpolyglot . Sembra fare ciò che dice abbastanza attendibilmente

  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); 

Se servire HTTP e HTTPS su una singola porta è un requisito assoluto, è ansible indirizzare direttamente la richiesta all’implementazione HTTP pertinente, anziché eseguire il piping del socket su un’altra porta.

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; }; 

Se è puro modulo Node.JS HTTP, puoi provare questo:

 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 }