Utilisez à la fois http et https pour socket.io

j'essaie de faire une prise.io travailler à la fois sur les connexions http et https , mais il semble que ma configuration ne puisse fonctionner que sur l'une d'entre elles.

avec la prise d'options de configuration ci-dessous.io peut accéder à mon application par https , mais en essayant d'accéder par http il ne peut pas se connecter et je reçois des erreurs.

    var app = express()
  , http= require('http').createServer(app)
  , https = require('https').createServer(options, app)
  , io = require('socket.io').listen(https, { log: false })

Et plus tard, j'ai ce

http.listen(80, serverAddress);
https.listen(443, serverAddress);

côté client, j'ai ceci:

<script src='/socket.io/socket.io.js'></script>

var socket = io.connect('https://<%= serverAddress %>', {secure: true, 'sync disconnect on unload' : true});

bien sûr, si je commute le http avec les options https sur les fonctions .listen et .connect du serveur et du client respectivement, j'obtiens le résultat inverse. Socket.io peut accéder par http et non par https.

comment y parvenir? J'en ai besoin principalement parce qu'il s'agit d'une application facebook, donc elle doit fournir à la fois des options de connexion http et https. selon facebook règles.

Edit: Dans le cas où il aide à résoudre le problème, l'erreur que je reçois est le ci-dessous

Failed to load resource: the server responded with a status of 404 (Not Found) http://DOMAIN/socket.io/socket.io.js

et pour cette raison j'en ai d'autres comme:

Uncaught ReferenceError: io is not defined 
12
demandé sur Vassilis Barzokas 2013-06-25 01:09:30

5 réponses

je crois que le problème est dans votre façon de configurer socket.io sur le côté serveur et sur le client.

Voici comment je l'ai fait fonctionner (juste pour vous).

serveur:

var debug = require('debug')('httpssetuid');
var app = require('../app');
var http = require('http');
var https = require('https');
var fs = require('fs');
var exec = require('child_process').exec;
var EventEmitter = require('events').EventEmitter;
var ioServer = require('socket.io');

var startupItems = [];
startupItems.httpServerReady = false;
startupItems.httpsServerReady = false;

var ee = new EventEmitter();

ee.on('ready', function(arg) {
  startupItems[arg] = true;
  if (startupItems.httpServerReady && startupItems.httpsServerReady) {
    var id = exec('id -u ' + process.env.SUDO_UID, function(error, stdout, stderr) {
      if(error || stderr) throw new Error(error || stderr);
      var uid = parseInt(stdout);
      process.setuid(uid);
      console.log('de-escalated privileges. now running as %d', uid);
      setInterval(function cb(){
        var rnd = Math.random();
        console.log('emitting update: %d', rnd);
        io.emit('update', rnd);
      }, 5000);
    });
  };
});

app.set('http_port', process.env.PORT || 80);
app.set('https_port', process.env.HTTPS_PORT || 443);

var httpServer = http.createServer(app);

var opts = {
  pfx: fs.readFileSync('httpssetuid.pfx')
};
var httpsServer = https.createServer(opts, app);

var io = new ioServer();

httpServer.listen(app.get('http_port'), function(){
  console.log('httpServer listening on port %d', app.get('http_port'));
  ee.emit('ready', 'httpServerReady');
});

httpsServer.listen(app.get('https_port'), function(){
  console.log('httpsServer listening on port %d', app.get('https_port'));
  ee.emit('ready', 'httpsServerReady');
});

io.attach(httpServer);
io.attach(httpsServer);

io.on('connection', function(socket){
  console.log('socket connected: %s', socket.id);
});

Client:

script(src='/socket.io/socket.io.js')
script.
  var socket = io();
  socket.on('update', function(update){
    document.getElementById('update').innerHTML = update;
  });

Voici les points clés pour le serveur:

  1. require socket.io mais ne le fais pas appelez sa méthode listen (en supposant que http et https sont déjà requis). Au lieu de cela, il suffit de garder la référence. (var ioServer = require ('socket.io'))
  2. créer votre serveur http & https
  3. créer une nouvelle instance de ioServer
  4. lient vos serveurs http et https (.listen)
  5. attacher les instances du serveur http&https à l'instance io. (.écouter est un alias .pièce jointe)
  6. setup io événement.

et le client (syntaxe jade mais vous avez l'idée):

  1. inclure le support.io balise de script
  2. appel d'io et de capture de référence
  3. configurer vos gestionnaires d'événements

sur le client vous n'avez pas besoin d'appeler io.connecter.)( En outre, Je ne suis pas sûr de vos options là-bas. On dirait que vous avez une faute de frappe (,,) et je ne trouve aucune référence à secure: true dans la documentation 1.0.

13
répondu a_arias 2014-06-25 22:23:55

sans doute, le noeud.js server object pour HTTP et HTTPS devrait avoir la possibilité d'écouter sur un nombre arbitraire de ports et d'interfaces, avec et sans SSL, mais cela ne semble pas être actuellement mis en œuvre. (J'ai pu obtenir qu'un serveur écoute sur deux ports en passant un second serveur qui n'avait pas d'écouteur de requête comme argument "handle" au serveur.interface listen(handle, [callback]), en plus du serveur.écouter(port, [nom d'hôte], [carnet], [rappel]), mais il n'a ne fonctionne pas avec des serveurs SSL/non-SSL mélangés.)

la stunnel contournement déjà mentionné est bien sûr une option viable, mais s'il n'est pas souhaitable d'installer un logiciel séparé (pour éviter les non-noeuds.js dependencies), le même effet tunnel peut être réalisé nativement dans le noeud.js à la place (en supposant HTTP sur le port 80 et HTTPS sur le port 443):

var fs = require('fs');
var net = require('net');
var tls = require('tls');
var sslOptions = {
    key: fs.readFileSync('server-key.pem'),
    cert: fs.readFileSync('server-cert.pem')
};
tls.createServer(sslOptions, function (cleartextStream) {
    var cleartextRequest = net.connect({
        port: 80,
        host: '127.0.0.1'
    }, function () {
        cleartextStream.pipe(cleartextRequest);
        cleartextRequest.pipe(cleartextStream);
    });
}).listen(443);

cela aura le même effet que d'utiliser stunnel . En d'autres termes, il évitera d'avoir besoin de deux sockets séparés.IO server instances, tout en faisant également le noeud.module js "https" redondant.

4
répondu Otto G 2014-03-25 17:08:58

j'ai fait quelque chose de similaire et il fallait deux socket.io instances. Quelque chose comme ceci:

var express = require('express');
var oneServer = express.createServer();
var anotherServer = express.createServer();
var io = require('socket.io');

var oneIo = io.listen(oneServer);
var anotherIo = io.listen(anotherServer);

bien sûr que vous aurez besoin d'injecter des messages deux fois: pour les deux socket.io instances.

une bonne option est de déléguer la manipulation SSL à stunnel et d'oublier SSL dans votre code.

2
répondu MrTorture 2013-06-24 22:26:43

je suppose que les requêtes D'origine croisée pourraient être la raison pour laquelle vous obtenez des erreurs. Changement de protocole est considéré comme changement dans le domaine. Ainsi, pour la page servie via http serveur accédant https serveur (serveur websocket attaché à elle) peut jeter des erreurs de sécurité. Voir un exemple ici sur la façon d'activer CORS dans express.

vous devez aussi changer * dans l'en-tête à http://serverAddress , https://serverAddress . Autoriser tous les sites n'est pas une bonne chose de l'idée, de l'utiliser pour le test.

la même chose est vraie si vous essayez D'AJAX entre vos serveurs http et https . Veuillez signaler les erreurs, juste pour être sûr.

0
répondu user568109 2013-06-27 04:40:35

j'ai résolu les problèmes en utilisant une approche différente, j'ai configuré le serveur pour supporter seulement le transport en clair, et j'ai utilisé stunnel pour le support https.

pour des informations sur la façon d'installer stunnel vous pouvez cocher cette case post .

puis, utilisé la configuration con suivante:

#/etc/stunnel/stunnel.conf
cert = /var/www/node/ssl/encryption.pem
[node]
accept = 443
connect = 80

enfin, j'ai utilisé ce qui suit pour connecter les clients:

var socket = that.socket = io.connect('//'+server);

ce sera auto détecter le schéma du navigateur et se connecter en utilisant http/https en conséquence.

0
répondu Kuf 2017-05-23 12:17:08