Socket.io: 1.0.0-pre“会话 ID 未知”

创建于 2014-04-23  ·  38评论  ·  资料来源: socketio/socket.io

HTTP 响应
{"code":1,"message":"会话 ID 未知"}

调试=socket.io:*

socket.io:socket 加入房间 2d1DHsPAtc1Sspm6AAAE +0ms
socket.io: id 为 rwLW7JMBp6E4TyexAAAG +3s 的服务器传入连接
socket.io:client 连接到命名空间/+3s
socket.io:namespace 将套接字添加到 nsp / +3s
socket.io:socket socket connected - 写包+3s
socket.io:socket 加入房间 rwLW7JMBp6E4TyexAAAG +0ms
socket.io:client 写入数据包 {"type":0,"nsp":"/"} +1ms
socket.io:client 写入数据包 {"type":2,"data":["news",{"hello":"world"}],"nsp":"/"} +0ms
socket.io:socket 加入房间 rwLW7JMBp6E4TyexAAAG +1ms
socket.io: id 为 03Izy4YOxaYm5-d-AAAH +1s 的服务器传入连接
socket.io:client 连接到命名空间/+1s
socket.io:namespace 将套接字添加到 nsp / +1s
socket.io:socket socket connected - 写入数据包+1s
socket.io:socket 加入房间 03Izy4YOxaYm5-d-AAAH +0ms
socket.io:client 写入数据包 {"type":0,"nsp":"/"} +1ms
socket.io:client 写入数据包 {"type":2,"data":["news",{"hello":"world"}],"nsp":"/"} +0ms

并且套接字立即断开

最有用的评论

对我来说,它是使用 nginx ssl http2,它正在轮询,所以好的配置是:

 const ioSocket = io('', {
      // Send auth token on connection, you will need to DI the Auth service above
      // 'query': 'token=' + Auth.getToken()
      path: '/socket.io',
      transports: ['websocket'],
      secure: true,
    });

所有38条评论

感谢您报告@ceram1。 你能用 1.0.2 重复这个问题吗? 如果是这样,那么查看客户端调试日志和/或获取一些示例代码来重现问题会很有趣。 会有很大帮助。 :)

啊..对不起...邮件是垃圾邮件...我会尽快测试它

+1
我们在 2 节点集群(由 socket.io-redis 支持)上的高连接率下注意到了这一点。

嗨,大家好,
套接字.io 1.0.6
socket.io-redis

回复:
{"code":1,"message":"会话 ID 未知"}

在 Heroku 上只有 1 个以上的实例。
一个实例一切正常(我们喜欢它),但有 2 个或更多实例却失败了。 400 错误。

初始化:
io = require('socket.io')(compound.server);

io.adapter(redisSocket({
    host: redisHost
    , port: redisPort
    , pubClient: pub
    , subClient: sub
}));

sub = redis.createClient(redisPort, redisHost,{return_buffers:true});
pub = redis.createClient(redisPort, redisHost,{return_buffers:true});
客户端 = redis.createClient(redisPort, redisHost,{return_buffers:true});

如果你愿意,我可以通过 Skype 分享你的屏幕,我们可以通过它。 网上到处都是这个错误

这里有什么新东西??

我现在实际上面临着同样的问题。 在一个实例中一切运行良好,当有多个实例运行时发生 400 错误。

附言。 我的运行版本为 1.0.6。

+1

好的,如果您想运行集群,最简单的方法是继续调用库 socketcluster。
虽然它基于engine.io,但它与socket.io 足够接近
https://github.com/TopCloud/socketcluster

+1,如果我在 ELB 之后设置了多个实例,我会遇到这个问题。

+1

嗯..我不能再犯这个错误了..(我没有它的来源,因为一些测试失败了)
也许环境设置可能是一个原因。

我知道有什么问题。 像池这样的所有请求每次都通过端口调用同一个实例。
但就我而言,它不起作用,因为我在 heroku 上。 而且 heroku 不支持通过端口访问实例。 它总是通过自己的负载均衡器选择实例。
问题在这里:
socket.io/node_modules/engine.io/lib/server.js 在函数“verify”上有变量“clients”,它分别存在于每个实例上。 因此,如果请求来自不同的实例,它会返回 400。

啊..我没有聚集在测试代码中。 也许这就是为什么我不能再成功了

这是解决此问题的另一种解决方案。 但是,从大多数用例来看,这个解决方案并不好...

我想出的最佳解决方案是给每个实例(套接字服务器)一个不同的端口,并将实例的地址与连接到它的客户端数量存储在 redis 中。 然后让客户端在连接或重新连接之前向单独的节点应用程序(套接字管理器)询问套接字服务器地址。 然后套接字管理器选择连接最少的 socket.io 服务器。 它并不漂亮,但它确实有效并且可以缩放。

https://github.com/Automattic/socket.io/issues/1636

只是说,有同样的问题。 然后我认为我正在通过 nginx 处理请求。 添加了适当的 nginx 配置,之后一切都很好。

http://socket.io/docs/using-multiple-nodes/

您需要上游服务器定义中的 ip_hash 和一些标头。

@dux对 Heroku 有用吗? 我不认为我们可以更改 nginx 配置。

ups,我不知道这是heroku独有的线程。 不,这是香草 nginx 前端服务器解决方案。

如果有人可以找到 HEROKU 的解决方案,请在此处发布,这将非常有帮助:)

@miklacko经过大量尝试和错误后,我以这个配置结束(请记住,我没有时间测试消息是否在浏览器之间共享。但我可以测试的是我之间有稳定的连接客户端和服务器使用集群 express 4.x 和套接字 1.x。

express.js

var sio_redis = require('socket.io-redis'),
    url = require('url'),
    http = require('http'),
       // other imports... 

// Some express set up

// CookieParser should be above session
    app.use(cookieParser());

    var sessionStore = new mongoStore({
        db: db.connection.db,
        collection: config.sessionCollection
    });
    // Express MongoDB session storage
    var sessionMiddleware = session({
        secret: config.sessionSecret,
        store: sessionStore
    });

    app.use(sessionMiddleware);

    // Create Server and Socket.io
    var server = http.createServer(app);
    var sio = require('socket.io')(server);

    if(process.env.REDISCLOUD_URL){
        var redisURL = url.parse(process.env.REDISCLOUD_URL);
        redisURL.password = redisURL.auth.split(':')[1];
        var pub = require('redis').createClient(redisURL.port, redisURL.hostname, {auth_pass: redisURL.password, return_buffers: true});
        var sub = require('redis').createClient(redisURL.port, redisURL.hostname, {auth_pass: redisURL.password, return_buffers: true});
        sio.adapter(sio_redis({pubClient: pub, subClient: sub}));
    } else {
        sio.adapter(sio_redis({ host: 'localhost', port: 6379 }));
    }

    // Authenticate Socket.io using Cookie Auth
    sio.use(function(socket, next) {
        var handshake = socket.handshake;

        if (handshake.headers.cookie) {
            var req = {
                headers: {
                    cookie: handshake.headers.cookie
                }
            };

            cookieParser(config.sessionSecret)(req, null, function(err) {
                if (err) {
                    return next(err);
                }
                var sessionID = req.signedCookies['connect.sid'] || req.cookies['connect.sid'];
                sessionStore.get(sessionID, function (err, session) {
                    if (err) {
                        return next(err);
                    }

                    if (session) {
                        next();
                    } else {
                        return next(new Error('Invalid Session'));
                    }
                });
            });
        } else {
            next(new Error('Missing Cookies'));
        }
    });

// other express middleware set up
          // Handle Connection and disconnection
         sio.sockets.on('connection', function(socket) {
        console.log('user connected');
        socket.on('disconnect', function(){
            console.log('user disconnected');
        });
    });

    return server;

server.js(整个文件)

'use strict';
/**
 * Module dependencies.
 */
var init = require('./config/init')(),
    config = require('./config/config'),
    mongoose = require('mongoose'),
    cluster = require('cluster'),
    _ = require('lodash');


// Bootstrap db connection
var db = mongoose.connect(config.db);

// Init the express application
var server = require('./config/express')(db);

// Bootstrap passport config
require('./config/passport')();

// Start server.
var numCPUs = Math.ceil(require('os').cpus().length / 2);
if (cluster.isMaster) {
    var workers = [];

    // Helper function for spawning worker at index 'i'.
    var spawn = function(i) {
        workers[i] = cluster.fork();
        console.log('worker ' + workers[i].process.pid + ' created');

        // Optional: Restart worker on exit
        // workers[i].on('exit', function(worker, code, signal) {
        //  console.log('respawning worker', i);
        //  spawn(i);
        // });

        cluster.on('exit', function(worker, code, signal) {
            console.log('worker ' + worker.process.pid + ' died');
        });
    };

    // Spawn workers.
    for (var i = 0; i < numCPUs; i++) {
        spawn(i);
    }
} else {
    server.listen(config.port, function () {
        console.log('server started on ' + config.port + ' port');
    });
}

index.html(这里最重要的部分)

<script src="/socket.io/socket.io.js"></script>
    <script>
        var socket = io.connect({transports: ['websocket']});
    </script>

我们需要声明只在 Heroku 中使用websocket协议。 因为 xhr-polling 不起作用! 不知道为什么。

我希望今天我可以测试一下以socket/redis为思想的浏览器之间的通信。 我将分享结果。

@gonzalodiaz非常感谢! 下周我会试试,如果我发现一些错误或改进,我会告诉你。

@gonzalodiaz完美运行。 唯一不好的是旧浏览器不支持 websockets http://caniuse.com/#feat =websockets。

再次感谢你。

@miklacko很高兴知道它对您有用。 它对我也很有效:) - 如果您找到旧浏览器的解决方案,请告诉我。 现在对我来说这不是问题,但如果有备份就好了。

当客户端使用长轮询传输,而服务器使用集群模式时会出现此问题。

使用粘性会话将解决这个问题。

@nauu Heroku 不支持粘性会话。

The Heroku routing infrastructure does not support “sticky sessions”. 
Requests from clients will be distributed randomly to all dynos running your application.

https://devcenter.heroku.com/articles/java-faq

@gonzalodiaz Heroku 可以运行集群并在不同的端口监听吗?

如果可以,您可以使用 nginx 反向代理来自客户端的请求。 并使用 nginx 的粘性会话模块。

@nauu不,Heroku 不支持监听不同的端口。 Heroku 在环境变量中设置端口,并在内部分配测功机之间的负载。 这真的很痛苦。

因此,关于 Heroku 上的这个错误,如果您想使用支持所有 socket.io 而不仅仅是 Web 套接字的集群之类的东西,没有解决方案?

谢谢!

您可以通过这种方式在本地模拟 heroku:

1- npm 安装工头 -g
2-回显“网络:节点app.js”> Procfile
3- nf 开始 -x 3000 网络=3

这将在端口 5001、5002 和 5003 上启动您的服务器 (app.js) 的 3 个实例,但您可以通过端口 3000 上的反向代理访问它们。

启动它并尝试建立 websocket 连接,您将看到与 heroku 相同的问题。 node-foreman 是在本地模拟 heroku 环境的好方法。 需要记住的重要一点是,尽管您可以直接访问每个本地实例,但您只能访问 Heorku 上的负载均衡器(上例中的端口 3000)

什么是好的解决方案?

@ceram1你解决问题了吗?

+1

@gonzalodiaz感谢您提及transports: ['websocket']

对于那些在亚马逊 ELB 背后遇到此问题的人,请确保启用应用程序控制的会话粘性 (http://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-sticky-sessions.html)。 这为我解决了这个问题。

伙计们阅读这篇文章https://devcenter.heroku.com/articles/node-websockets
最后你会发现使用 Socket.io 的应用程序应该启用会话亲和性
然后继续https://devcenter.heroku.com/articles/session-affinity
然后放入 Heroku Toolbelt CLI heroku features:enable http-session-affinity --app APP
而且我很高兴在缩放的测功机上工作 socket.io。

对我来说,它是使用 nginx ssl http2,它正在轮询,所以好的配置是:

 const ioSocket = io('', {
      // Send auth token on connection, you will need to DI the Auth service above
      // 'query': 'token=' + Auth.getToken()
      path: '/socket.io',
      transports: ['websocket'],
      secure: true,
    });

@p3x-robot 我是通过这种方法修复的

此页面是否有帮助?
0 / 5 - 0 等级