Socket IO только сеанс не сохраняется

Я использую 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".

Что я делаю неправильно? Что мне не хватает для того, чтобы сессия сохранялась, как ожидалось?

Ответ 1

Проблема заключается в том, что вы используете cookie-session, а socket.io не позволяет устанавливать cookie из-за спецификации XMLHttpRequest, также у вас нет 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 для продолжения сеансов или некоторых "взломать", чтобы установить его в рукопожатие.

Другой вариант - не использовать сеансы вообще и просто установить свойство в объекте socket или в другом объекте javascript, но в этом случае вы не можете разделить объект между серверами/службами.

Ответ 2

  • По-прежнему доступны заголовки.
  • Вы можете сохранять данные на стороне сервера для каждого сокета: socket.my_value = "любой тип данных";
  • Вы можете сохранить данные в объекте io.sockets, io.my_value = "любой тип данных"

Итак, пример:

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