如何与Socket.IO 1.x和Express 4.x共享会话?

Mus*_*afa 82 session node.js express socket.io

如何与Socket.io 1.0和Express 4.x共享会话?我使用Redis商店,但我认为这无关紧要.我知道我必须使用中间件来查看cookie和获取会话,但不知道如何.我搜索但找不到任何工作

    var RedisStore = connectRedis(expressSession);
    var session = expressSession({
        store: new RedisStore({
            client: redisClient
        }),
        secret: mysecret,
        saveUninitialized: true,
        resave: true
    });
    app.use(session);

    io.use(function(socket, next) {
        var handshake = socket.handshake;
        if (handshake.headers.cookie) {
            var str = handshake.headers.cookie;
            next();
        } else {
            next(new Error('Missing Cookies'));
        }
    });
Run Code Online (Sandbox Code Playgroud)

Epe*_*eli 198

解决方案非常简单.它没有很好的记录.也可以使用快速会话中间件作为Socket.IO中间件,使用这样的小型适配器:

sio.use(function(socket, next) {
    sessionMiddleware(socket.request, socket.request.res, next);
});
Run Code Online (Sandbox Code Playgroud)

这是Express 4.x,Socket.IO 1.x和Redis的完整示例:

var express = require("express");
var Server = require("http").Server;
var session = require("express-session");
var RedisStore = require("connect-redis")(session);

var app = express();
var server = Server(app);
var sio = require("socket.io")(server);

var sessionMiddleware = session({
    store: new RedisStore({}), // XXX redis server config
    secret: "keyboard cat",
});

sio.use(function(socket, next) {
    sessionMiddleware(socket.request, socket.request.res, next);
});

app.use(sessionMiddleware);

app.get("/", function(req, res){
    req.session // Session object in a normal request
});

sio.sockets.on("connection", function(socket) {
  socket.request.session // Now it's available from Socket.IO sockets too! Win!
});


server.listen(8080);
Run Code Online (Sandbox Code Playgroud)

  • 这个解决方案太美了,让我哭了. (52认同)
  • 你能帮我解决一下吗?我只得到这个数据{cookie:`{path:'/',_ expires:null,originalMaxAge:null,httpOnly:true,secure:true}}`但是如果我在路线中打印会话,我得到所有的会话变量我已设置(用户名,ID等) (16认同)
  • 这很棒.哦,伙计,我希望我可以通过我的屏幕来亲吻你,@ Epeli (10认同)
  • 这应该完全添加到他们的文档中.身份验证文档目前非常轻松. (6认同)
  • 通过几次修改,这很有效.但我无法从socket.io写入会话.我找到了一个满足我所有需求的NPM包,并且需要与实现这个答案的努力相同.https://www.npmjs.com/package/express-socket.io-session (4认同)
  • 这对我来说"有用",但是我的Express会话ID与我的socket.io会话ID不同......也许我真的不希望它们是相同的吗? (3认同)
  • socket.request.res未定义的原因是什么? (3认同)
  • 这个解决方案很棒!...直到我需要在socket.on()中将数据保存到会话中,我发现它只有一种方式.有没有办法让它在两个方面都有效? (3认同)
  • 我有simmilar问题,@youbetternot并找到解决方法,这一问题更改为:`sessionMiddleware(socket.request,{},下一个);` (3认同)
  • 就我而言,socket.request.res是未定义的.你知道问题是什么吗? (2认同)
  • 与@AlexMills相同的问题,快递会话ID和套接字会话ID似乎有所不同......这是一个[不同的问题](http://stackoverflow.com/questions/33913758/express-session-isnt-setting-session-cookie -while-using-with-socket-io)与整个代码 (2认同)
  • 很抱歉恢复此线程,但是我遇到了与 @BobbyShark 和 @luff 相同的问题。路夫说他能弄明白,但没有说是怎么弄的。我正在使用 `req.session.propName = value` 存储会话变量。这些不会出现在`socket.request.session`中。 (2认同)
  • 我爱你真实 (2认同)
  • 节省时间的人!! 非常感谢,它充当魅力. (2认同)

poo*_*zko 5

就在一个半月前,我处理了相同的问题,然后写了一篇有关该主题的广泛博客文章,并与托管在GitHub上的完全正常的演示应用程序一起使用。该解决方案依赖于express-sessioncookie-parserconnect-redis节点模块来捆绑一切。它允许您从REST和Sockets上下文访问和修改会话,这非常有用。

两个关键部分是中间件设置:

app.use(cookieParser(config.sessionSecret));
app.use(session({
    store: redisStore,
    key: config.sessionCookieKey,
    secret: config.sessionSecret,
    resave: true,
    saveUninitialized: true
}));
Run Code Online (Sandbox Code Playgroud)

...和SocketIO服务器设置:

ioServer.use(function (socket, next) {
    var parseCookie = cookieParser(config.sessionSecret);
    var handshake = socket.request;

    parseCookie(handshake, null, function (err, data) {
        sessionService.get(handshake, function (err, session) {
            if (err)
                next(new Error(err.message));
            if (!session)
                next(new Error("Not authorized"));

            handshake.session = session;
            next();
        });
    });
});
Run Code Online (Sandbox Code Playgroud)

它们与我制作的一个简单的sessionService模块一起使用,该模块允许您对会话执行一些基本操作,并且代码如下所示:

var config = require('../config');

var redisClient = null;
var redisStore = null;

var self = module.exports = {
    initializeRedis: function (client, store) {
        redisClient = client;
        redisStore = store;
    },
    getSessionId: function (handshake) {
        return handshake.signedCookies[config.sessionCookieKey];
    },
    get: function (handshake, callback) {
        var sessionId = self.getSessionId(handshake);

        self.getSessionBySessionID(sessionId, function (err, session) {
            if (err) callback(err);
            if (callback != undefined)
                callback(null, session);
        });
    },
    getSessionBySessionID: function (sessionId, callback) {
        redisStore.load(sessionId, function (err, session) {
            if (err) callback(err);
            if (callback != undefined)
                callback(null, session);
        });
    },
    getUserName: function (handshake, callback) {
        self.get(handshake, function (err, session) {
            if (err) callback(err);
            if (session)
                callback(null, session.userName);
            else
                callback(null);
        });
    },
    updateSession: function (session, callback) {
        try {
            session.reload(function () {
                session.touch().save();
                callback(null, session);
            });
        }
        catch (err) {
            callback(err);
        }
    },
    setSessionProperty: function (session, propertyName, propertyValue, callback) {
        session[propertyName] = propertyValue;
        self.updateSession(session, callback);
    }
};
Run Code Online (Sandbox Code Playgroud)

由于整个代码比这更多(例如初始化模块,在客户端和服务器端使用套接字和REST调用),因此我不会在此处粘贴所有代码,您可以在GitHub上查看您可以随心所欲地做任何事情。


小智 5

express-socket.io-session

是针对您的问题的现成解决方案。通常在 socket.io 端创建的会话与在 express.js 中创建的会话具有不同的 sid

在知道这个事实之前,当我努力寻找解决方案时,我发现了一些奇怪的东西。从 express.js 实例创建的会话可以在 socket.io 端访问,但相反的情况则不可能。很快我就知道我必须通过管理 sid 来解决这个问题。但是,已经有一个包可以解决这个问题。它有据可查,可以完成工作。希望能帮助到你