对于socket.io使用http和https

我试图使socket.io工作在httphttps连接上,但似乎与我的configuration,它只能在其中之一工作。

使用下面的configuration选项,socket.io可以通过https访问我的应用程序,但是当试图通过普通的http访问时,它不能连接,我收到错误。

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

后来我有这个

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

在客户端我有这个:

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

当然,如果我切换服务器和客户端的.listen.listen函数的HTTPS选项分别我有相反的结果。 Socket.io可以通过http访问,而不是通过https访问。

怎么可能做到这一点? 我需要它主要是因为它是关于一个Facebook应用程序,所以它必须根据Facebook规则提供http和https连接选项。

编辑:如果它有助于解决问题,我收到的错误是在下面

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

正因为如此,我得到了其他人如:

 Uncaught ReferenceError: io is not defined 

我相信问题是在服务器端客户端设置socket.io的方式。

这就是我的工作方式(只为你)。

服务器:

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

客户:

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

这里是服务器的关键点:

  1. 需要socket.io,但不要调用它的监听方法(假设已经需要http和https)。 相反,只是保持参考。 (var ioServer = require('socket.io'))
  2. 创build你的http和https服务器
  3. 创build一个ioServer的新实例
  4. 绑定你的http和https服务器(.listen)
  5. 将http和https服务器实例附加到io实例。 (.listen是.attach的别名)
  6. 设置io事件。

和客户端(玉语法,但你明白了):

  1. 包括socket.io脚本标记
  2. 调用io并捕获参考
  3. 设置您的事件处理程序

在客户端上,您不需要调用io.connect()。 此外,我不确定你的select。 它看起来像你有一个错字(,,),我找不到在1.0文档中的任何安全:真的引用。

可以说,HTTP和HTTPS的node.js服务器对象应该具有监听任意数量的端口和接口的能力,可以使用和不使用SSL,但目前看来并没有实现。 (除了server.listen(port)之外,我还可以通过向server.listen(handle,[callback])接口传递没有请求侦听器的第二个服务器作为“handle”参数, ,[主机名],[待办事项],[callback]),但它不适用于混合的SSL /非SSL服务器。

已经提到的stunnel解决方法当然是一个可行的select,但是如果不希望安装一个独立的软件(为了避免非node.js依赖),相同的隧道可以在node.js中本地实现(假设端口80上的HTTP和端口443上的HTTPS):

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

这与使用stunnel具有相同的效果。 换句话说,它将避免需要两个独立的socket.io服务器实例,同时也使得node.js“https”模块冗余。

我做了类似的事情,它需要两个socket.io实例。 像这样的东西:

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

当然,你将需要注入两次消息:两个socket.io实例。

一个很好的select是委托SSL处理,以便在代码中使用SSL。

我猜测交叉来源请求可能是你得到错误的原因。 协议的变化被认为是在域中的变化。 所以对于通过http服务器访问https服务器(连接到它的websocket服务器)的页面可能会引发安全错误。 在这里看一个如何启用CORS的例子。

你也应该在标头中将*改为http://serverAddress , https://serverAddress 。 允许所有网站不是一个好主意,使用它进行testing。

如果您尝试在httphttps服务器之间进行AJAX,情况也是如此。 请发布错误,只是为了确保它。

我使用不同的方法解决了问题,我将服务器configuration为只支持未encryption的传输,并使用stunnel进行https支持。

有关如何安装stunnel信息,您可以查看这篇文章 。

然后,使用以下conconfiguration:

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

最后,我使用以下来连接客户端:

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

这将自动检测浏览器scheme并相应地使用http / https进行连接。