无法创build与Node.js socket.io服务器的跨域websocket连接

根据我的search,这不应该那么辛苦,到目前为止我已经尝试了许多没有运气的东西。 我有一个在Heroku上运行的Node.js服务器,它创build了一个socket.io服务器(我也曾尝试在Nodejitsu上托pipe它,但没有帮助)。 socket.io套接字连接没有问题,如果我从实际的Node.js服务器,我想创build一个websocket连接的服务页面,但我不能使任何我的跨域套接字连接尝试工作。

我试图做一个跨域连接到这个socket.io服务器几种方式:

(1)一个简单的本地HTML文件,其中包含一些脚本,用于从节点服务器(使用$ .getScript)成功获取客户端socket.io库,然后尝试创build套接字连接(var socket = io.connect('nodejs_server_hostname:port_num ');),失败。

(2)在本地运行Rails应用程序服务器(开发模式),为包含JavaScript的客户端提供响应,尝试以与方法(1)相同的方式形成websocket连接,并且失败

(3)在Heroku中托piperails应用程序,并执行与方法(2)相同的操作。 这也失败了。 我确保按照Heroku文档( https://devcenter.heroku.com/articles/heroku-labs-websockets )中的说明启用websockets。 如果请求是从客户端尝试与之build立socket.io连接的实际的Node.js服务器提供的,那么一切都可以正常工作。

所有三次尝试都会触发socket.socket.on('error')事件。

我已经尝试使用以下代码修改rails应用程序中的http响应头文件:

response.headers['Access-Control-Allow-Origin'] = '*' 

这正确地设置标题(我从轨道服务器请求页面后检查),但它不修复套接字连接问题。

我在执行日志logging的Node.js服务器上创build了一个socket-io授权callback函数,看起来这个callback函数根本就没有碰到跨域套接字连接尝试。 所以看起来Node.js服务器甚至从来没有看到websocket连接尝试,这对我来说是相当混乱的。

下面我将粘贴所有相关的代码文件。

Node.js服务器文件:

 var http = require('http'), express = require('express'), whiskers = require('whiskers'), redis = require('redis'), port = process.env.PORT || 5000, app = express(), server = http.createServer(app).listen(port), io = require('socket.io').listen(server); console.log('---- ' + port); console.log(port); console.log('---- ' + port); io.configure(function () { io.set('authorization', function (handshakeData, callback) { console.log("-- inside io.set('authorization, cb)") console.log('-- handshakeData:'); console.log(handshakeData); console.log('-- end of handshakeData logging --'); callback(null, true); // error first callback style }); }); app.configure(function() { app.use(express.static(__dirname + '/public')); app.set('views', __dirname + '/views'); app.set('view options', { layout: false }); app.engine('.html', whiskers.__express); }); app.get('/', function(req, res) { res.render('index.html'); }); io.sockets.on('connection', function(socket) { console.log('---- new client connected ----'); console.log(socket); console.log('---- end of socket details logging for new client connection ----'); socket.emit('news', { hello: 'world' }); socket.on('my other event', function(data) { console.log("-- server -- inside socket.on 'my other event' callback"); console.log(data); }); socket.on('button clicked', function(data) { console.log("-- server -- inside socket.on 'button clicked' callback"); console.log(data); io.sockets.emit('news', { info: 'the button was clicked' }); }); }); 

这里是Rails应用程序的客户端JavaScript文件:

 $(document).ready(function() { console.log('-- inside chat.js -- document is ready'); $('#join-chat-container').hide(); $('#new-message-container').hide(); //$.getScript('http://node-server-for-rails-chat.herokuapp.com/socket.io/socket.io.js') $.getScript('http://node-server-for-rails-chat.jit.su/socket.io/socket.io.js') .done(function( script, textStatus ) { console.log("-- socket.io.js loaded and executed -- textStatus: " + textStatus); setup_socket(); }) .fail(function( jqxhr, settings, exception ) { console.log("-- socket.io.js load error -- exception:"); console.log(exception); console.log("-- jqxhr: " + jqxhr); }); }); function setup_socket() { //var socket = io.connect('node-server-for-rails-chat.herokuapp.com', { port: 19364 }); //var socket = io.connect('node-server-for-rails-chat.jit.su', { port: 5000 }); var socket = io.connect('node-server-for-rails-chat.herokuapp.com:27305'); socket.socket.on('error', function (reason) { console.log('--- cant connect'); console.log(reason); console.error('Unable to connect Socket.IO', reason); }); socket.on('connect_failed', function() { console.log('connect failed'); }); socket.on('connect', function() { console.log('successfully connected!'); }); socket.on('message', function (message_html) { console.log("-- client -- inside socket.on('message', cb) callback"); console.log("-- client -- message_html: " + message_html); add_message(message_html); }); if (!socket.socket.connected) { console.log(socket); console.log("-- Error connecting with socket"); } socket_loaded(socket); }; function socket_loaded(socket) { // this part contains irrelevant (not socket related) code } //more irrelevant code excluded for brevity (add_message function, plus other stuff) 

这是我在浏览器中本地打开的独立HTML文件:

 <!DOCTYPE html> <html> <head> <script type="text/javascript" src="http://code.jquery.com/jquery-git.js"></script> <script> $(document).ready(function() { if (typeof jQuery !== 'undefined') { console.log('-- client -- jQuery library loaded successfully'); $('#myButton').on('click', function() { console.log("-- client -- inside jquery '#myButton' click callback"); socket.emit('button clicked', { button: '#myButton' }); }); } $.getScript('http://node-server-for-rails-chat.herokuapp.com/socket.io/socket.io.js') .done(function( script, textStatus ) { console.log("-- socket.io.js loaded and executed -- textStatus: " + textStatus); socket_is_loaded(); }) .fail(function( jqxhr, settings, exception ) { console.log("-- socket.io.js load error -- exception:"); console.log(exception); console.log("-- jqxhr: " + jqxhr); }); }); function socket_is_loaded() { //var socket = io.connect('node-server-for-rails-chat.jit.su:5000'); var socket = io.connect('node-server-for-rails-chat.herokuapp.com:27305'); socket.socket.on('error', function (reason) { console.log('--- cant connect'); console.log(reason); console.error('Unable to connect Socket.IO', reason); }); socket.on('connect_failed', function() { console.log('connect failed'); }); socket.on('connect', function() { console.log('successfully connected!'); }); socket.on('news', function(data) { console.log("-- client -- inside socket.on 'news' callback"); console.log(data); //socket.emit('my other event', { my: 'data' }); }); } </script> </head> <body> <h1>Socket.io How-to-use Example Script</h1> <input type='button' id='myButton' value='click me!'/> </body> </html> 

有没有人有如何解决这个问题的想法? 谢谢一堆。

我有一个类似的设置运行,并不得不在节点快递Web服务器上configuration以下标题。

 app = require('express')(); ... app.use(function(req, res, next) { res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Methods', 'GET, OPTIONS'); res.header('Access-Control-Allow-Headers', 'Content-Type'); return next(); }); 

Socket.IO版本 – > 1.3.7 Express版本 – > 4.13.3

选项1:只强制使用Websockets

默认情况下,websockets是跨域。 如果你强制Socket.io只使用它作为连接客户端和服务器的手段,那么你很好。

服务器端

 //HTTP Server var server = require('http').createServer(app).listen(8888); var io = require('socket.io').listen(server); //Allow Cross Domain Requests io.set('transports', [ 'websocket' ]); 

客户端

 var connectionOptions = { "force new connection" : true, "reconnectionAttempts": "Infinity", //avoid having user reconnect manually in order to prevent dead clients after a server restart "timeout" : 10000, //before connect_error and connect_timeout are emitted. "transports" : ["websocket"] }; var socket = io("ur-node-server-domain", connectionOptions); 

而已。 问题? 不支持不支持websocket的浏览器(对于客户端)。 有了这个,你几乎杀死了Socket.io的魔法,因为它逐渐开始了长轮询,以后升级到websocket(如果客户端支持的话)。

如果您100%确定您的所有客户都将访问HTML5兼容的浏览器,那么您就可以走了。

选项2:在服务器端允许CORS,让Socket.io处理是使用websockets还是长时间轮询。

对于这种情况,您只需要调整服务器端设置。 客户端连接与往常一样。

服务器端

 //HTTP Server var express=require('express'); //Express instance var app = express(); //ENABLE CORS app.all('/', function(req, res, next) { res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Headers", "X-Requested-With"); next(); }); 

而已。 希望它可以帮助其他人。 请记住,对于第二个选项来说,// ENABLE CORS部分是您应用到您的快速实例(express())的第一件事是非常重要的;