仅套接字 IO 会话不持久

Posted

技术标签:

【中文标题】仅套接字 IO 会话不持久【英文标题】:Socket IO only session not persisting 【发布时间】:2016-04-20 14:14:01 【问题描述】:

我在我正在构建的聊天应用程序中使用Socket.io。我正在尝试设置会话,以便我可以在会话之间保持用户的登录。

以下是相关代码:

index.js(服务器)

var cookieParser = require('cookie-parser')();
var session = require('cookie-session')( secret: 'secret' );

app.use(cookieParser);
app.use(session);

io.use(function(socket, next) 
    var req = socket.handshake;
    var res = ;
    cookieParser(req, res, function(err) 
        if (err) return next(err);
        session(req, res, next);
    );
);


io.on('connection', function(socket)

    socket.on('test 1', function()
        socket.handshake.test = 'banana';
    );

    socket.on('test 2', function()
        console.log(socket.handshake.test);
    );
);

chat.js(客户端)

var socket = io();

socket.emit('test 1');
socket.emit('test 2');

上面的代码有效,它将按预期将banana 打印到控制台。但是,如果我像这样注释掉“测试 1”:

var socket = io();

// socket.emit('test 1');
socket.emit('test 2');

它将在控制台打印undefined

它是否仍然可以打印banana,因为它正在使用会话并且在请求之间持续存在?如果我颠倒调用“测试 1”和“测试 2”的顺序,我也会遇到同样的问题。

我做错了什么?为了让会话按预期持续存在,我缺少什么?

【问题讨论】:

socket.handshake.session.test = 'banana'; 用于test 1socket.handshake.session.test 用于test 2 是否有效? 【参考方案1】:

问题是您使用的是cookie-session,并且socket.io 不允许您设置cookie 由于XMLHttpRequest 的规范,而且您在Web 套接字中间没有request/response交易,所以你不能设置响应cookie。

使用您的中间件,您可以看到 cookie,但您不能在 socket.io 中设置它。 这个例子可以确保这一点:

io.use(function(socket, next) 
    var req = socket.request;
    var res = req.res;
    cookieParser(req, res, function(err) 
        if (err) return next(err);
        session(req, res, next);
    );
);

io.on('connection', function(socket)
    var req = socket.request;
    console.log(req.session.test)

    socket.on('test 1', function()
        req.session.test = 'banana';
    );

    socket.on('test 2', function()
        console.log(req.session.test);
    );
);

app.get('/', function(req, res) 
    console.log(req.session.test)
    if (!req.session.test) 
      req.session.test = 'banana request'
    
)      

您可以使用 redis 之类的东西来保持会话,或者使用一些“hack”来在握手中设置它。

另一种选择是根本不使用会话,只需在socket 对象或另一个 javascript 对象中设置属性,但在这种情况下,您无法在服务器/服务之间共享该对象。

How to share sessions with Socket.IO 1.x and Express 4.x? https://www.npmjs.com/package/express-socket.io-session https://github.com/rakeshok/socket.io-client-cookie http://www.w3.org/TR/XMLHttpRequest/ https://github.com/socketio/socket.io/blob/master/examples/chat/index.js#L35-L36 How to associate properties to socket.io object in Redis Store?

【讨论】:

【参考方案2】:
    仍然可以访问标题。 您可以在服务器端为每个套接字保存数据:socket.my_value = "any data type"; 您可以将数据保存在 io.sockets 对象中,io.my_value = "any data type"

所以,例如:

    io.on('connection', function(socket)
        var id = socket.handshake.query.id; //you can set this in client connection string http://localhost?id=user_id
        //Validate user, registered etc. and if ok/
        if(validateUser(id)) 
            //if this is reconnect
            if(io.sessions[id]) 
               socket.session_id = io.sessions[id].session_id;
             else 
               var session_id = random_value;
               socket.session_id = some_random_value;
               io.sessions[id] = 
                 user_id: id,
                 session_id: socket.session_id
               ;
            

            registerEvent(socket);
         else 
            socket.emit('auth_error', 'wrong user');
        
    );


function registerEvent(socket) 
    socket.on('some_event', function(data, callback) 
       if(!socket.session_id) 
         callback('unathorized');//or emit
         socket.emit('auth_error', 'unauthorized');
       

       //do what you want, user is clear
    );

【讨论】:

以上是关于仅套接字 IO 会话不持久的主要内容,如果未能解决你的问题,请参考以下文章

带有 socket.io 状态的 UseEffect 钩子在套接字处理程序中不持久

带有快速会话的 ReactJS 和 socket.io - 套接字未使用正确的会话并创建了许多其他会话

使用快速会话的套接字 IO - socket.request.res 未定义

如何将用户名从php会话存储到nodejs中的socket.io库和页面刷新时套接字连接断开。为啥?

socket.io 身份验证与共享会话数据,io.use() 如何工作

Socket.io 问题仅在移动设备上