Node.js,ws和express-session:如何从ws.upgradeReq获取会话对象

ale*_*oat 4 session websocket node.js express express-session

我有一个基于express,express-session和ws的应用程序(用于websocket支持).

我已使用此代码启用会话中间件:

app.use(session({secret: 'mysecret',resave: true,saveUninitialized: true,cookie: {}}));
Run Code Online (Sandbox Code Playgroud)

我可以在get处理程序中读取和保存会话变量:

app.get('/', function (req, res) {
  res.send('Hello World!');
  console.log(req.session.test);
  req.session.test="OK";
  req.session.save();
});
Run Code Online (Sandbox Code Playgroud)

(第一次打印"未定义",第二次按预期打印"OK")

现在我有一个websocket服务器,也是在同一个应用程序中由express处理,我想在req.session内部ws.on("connection",...)和内部获取对象ws.on("message",...).

问题是没有对原始req对象的引用,只是引用了一个upgradeReq是websocket的连接处理程序的包装器.检查此upgradeReq我可以找到包含会话cookie值的connect.sidin ws.upgradeReq.headers.cookie.

wss.on('connection', function connection(ws) {
  var location = url.parse(ws.upgradeReq.url, true);
  console.log(ws.upgradeReq.headers.cookie);
  //....
});
Run Code Online (Sandbox Code Playgroud)

在我的想法中可以通过req.session某种方式从中获取原始内容.

我怎么能做到这一点?

ale*_*oat 7

好的,我发现了一种研究快速会话源代码的无证方法.

首先,你需要cookiecookie-parser作为你的依赖.

所以,导入模块

var cookie = require('cookie');
var cookieParser = require('cookie-parser')
Run Code Online (Sandbox Code Playgroud)

然后,诀窍是在ws"连接"事件处理程序中解码签名的cookie,即处理websocket握手时.首先,您需要从cookie中解码为会话ID的connect.sid(仅当您使用快速会话进行会话管理时)

wss.on('connection', function connection(ws) {
    var cookies=cookie.parse(ws.upgradeReq.headers.cookie);
    var sid=cookieParser.signedCookie(cookies["connect.sid"],secret);
    ...
Run Code Online (Sandbox Code Playgroud)

TAke关心你在快递会话中为签名设置的秘密是相同的(app.use(session({secret: secret, resave: true, saveUninitialized: true, cookie: {},store:store})); 在此处)此时你在sid中有sessoinID,你想从快递会话中获取会话对象,这是通过的你从商店异步(有很多,阅读文档,目前我只用ExpressStore的ExpressStore测试).

为了获得会话,然后在上面的行之后使用此代码

...
store.get(sid,function(err, ss){
        store.createSession(ws.upgradeReq,ss)
    });
Run Code Online (Sandbox Code Playgroud)

回调函数将直接从商店为您提供会话对象(ss),但它是单独的,没有方法(只是一个反序列化的JSON).因此,我们再次使用我们传递upgradeReq和ss对象的store.createSession,这样我就有了一个具有所有记录方法的会话对象(所以我也可以从ws回调中修改会话).

新的会话对象可用于:

ws.upgradeReq.session
Run Code Online (Sandbox Code Playgroud)

注意:在商店异步返回ss对象之前,会话对象不可用,因此完成websocket事件绑定(例如on('message',...)传递给store.get的回调内部)是一个好习惯.

这是完整的代码:

wss.on('connection', function connection(ws) {
    var location = url.parse(ws.upgradeReq.url, true);
    //get sessionID
    var cookies = cookie.parse(ws.upgradeReq.headers.cookie);
    var sid = cookieParser.signedCookie(cookies["connect.sid"], secret);
    //get the session object
    store.get(sid, function (err, ss) {
        //create the session object and append on upgradeReq
        store.createSession(ws.upgradeReq, ss)
        //setup websocket bindings
        ws.on('message', function incoming(message) {
            console.log('received: %s', message);
            //..........
        });

    });
});
Run Code Online (Sandbox Code Playgroud)

那么,现在您可以使用ws和express-session一起管理会话数据.

我希望它会有所帮助!

  • 仅供参考,当与Passport一起使用时,这对我有用.在这种情况下,我最终在ws.upgradeReq.session.passport.user中找到了te用户.谢谢! (3认同)
  • @dritan最近在ws 3.0中发生了重大变化.ws.upgradeReq已删除.搜索"ws break change upgradeReq"将为您提供更多信息. (2认同)

dri*_*tan 5

我只是发现在3.0.0版本中,upgradeReq已从WebSocket中删除。现有alexroat代码的解决方法:

wss.on('connection', function connection(ws, req) {
    ws.upgradeReq = req;
    var location = url.parse(ws.upgradeReq.url, true);
    //get sessionID
    var cookies = cookie.parse(ws.upgradeReq.headers.cookie);
    var sid = cookieParser.signedCookie(cookies["connect.sid"], secret);
    //get the session object
    store.get(sid, function (err, ss) {
        //create the session object and append on upgradeReq
        store.createSession(ws.upgradeReq, ss)
        //setup websocket bindings
        ws.on('message', function incoming(message) {
            console.log('received: %s', message);
            //..........
        });
    });
});
Run Code Online (Sandbox Code Playgroud)