NodeJS HTTP et HTTPS sur le même port

j'ai cherché sur Google et en regardant stackoverflow, mais je ne trouve pas une réponse que j'aime ; -)

j'ai un serveur NodeJS qui tourne sur HTTPS et le port 3001. Maintenant, je voudrais récupérer toutes les requêtes HTTP entrantes sur le port 3001 et les rediriger vers la même URL mais sur HTTPS.

cela doit être possible. N'est-ce pas?

Merci!

32
demandé sur user2164996 2014-03-17 16:03:05

4 réponses

vous n'avez pas besoin d'écouter sur le même port si vous suivez la convention

par convention lorsque vous demandez http://127.0.0.1 votre navigateur essaiera de se connecter au port 80. Si vous essayez d'ouvrir https://127.0.0.1 , votre navigateur tentera de se connecter au port 443. Donc, pour sécuriser tout le trafic, il est tout simplement conventionnel d'écouter le port 80 sur http avec une redirection vers https où nous avons déjà un écouteur pour https pour le port 443. Voici le code:

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

Test avec https:

$ curl https://127.0.0.1 -k
secure!

avec 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

si vous devez écouter sur le même port

il n'y a pas de façon simple d'avoir http / https listen sur le même port. Le mieux est de créer un serveur proxy sur une simple socket réseau qui achemine les données vers (http ou https) en fonction de la nature de la connexion entrante (http vs. https).

Voici le code complet (basé sur https://gist.github.com/bnoordhuis/4740141 ) qui fait exactement cela. Il écoute localhost: 3000 et le redirige vers http (qui à son tour le redirige vers https) ou si la connexion est en https il le passe simplement à 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');
}

comme test, si vous le connectez avec https, vous obtenez le handler https:

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

si vous le connectez avec http, vous obtenez le gestionnaire de redirection (qui vous au gestionnaire 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
66
répondu basarat 2014-06-01 06:16:34

je sais que c'est une vieille question, mais je la pose simplement comme une référence pour quelqu'un d'autre. La façon la plus facile que j'ai trouvé était d'utiliser le https://github.com/mscdex/httpolyglot module . Semble faire ce qu'il dit assez fiable

    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);
11
répondu Prakash Rajagaopal 2015-09-19 06:54:58

si servir HTTP et HTTPS sur un seul port est une exigence absolue, vous pouvez afficher la requête directement dans L'implémentation HTTP concernée, plutôt que de rediriger la socket vers un autre port.

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

exemple.js

'use strict';
let express = require('express');
let fs = require('fs');
let io =  require('socket.io');

let httpx = require('./httpx');

let opts = {
    key: fs.readFileSync('./server.key'),
    cert: fs.readFileSync('./server.cert')
};

let app = express();
app.use(express.static('public'));

let server = httpx.createServer(opts, app);
let ws = io(server.http);
let wss = io(server.https);
server.listen(8080, () => console.log('Server started'));
11
répondu Jake Holzinger 2017-02-03 13:25:49

si C'est un noeud pur.Alors vous pouvez essayer ceci:

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
}
0
répondu micnic 2014-03-17 13:19:26