对于socket.io使用http和https
我试图使socket.io工作在http
和https
连接上,但似乎与我的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; });
这里是服务器的关键点:
- 需要socket.io,但不要调用它的监听方法(假设已经需要http和https)。 相反,只是保持参考。 (var ioServer = require('socket.io'))
- 创build你的http和https服务器
- 创build一个ioServer的新实例
- 绑定你的http和https服务器(.listen)
- 将http和https服务器实例附加到io实例。 (.listen是.attach的别名)
- 设置io事件。
和客户端(玉语法,但你明白了):
- 包括socket.io脚本标记
- 调用io并捕获参考
- 设置您的事件处理程序
在客户端上,您不需要调用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。
如果您尝试在http
和https
服务器之间进行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进行连接。