io.controller和io.middleware都无法获取到session,但app.controller中可以获取,请问是什么原因?
socket.io 和 http 不是一个模型来着
那我需要怎么做才可以拿到session呢?
请提供复现代码
module.exports = app => {
return function* (next) {
// this.socket.emit('res', 'connected!');
console.log(this.socket.handshake);
console.log(app.context.sessionOptions);
console.log(this.session.temp);
console.log('connected!');
yield* next;
console.log('disconnection!');
};
};
基本什么都还没开始处理,就是想先通过web api授权,并拿到session id,然后在socket.io这边可以直接使用session的内容
这样看不出什么来。请按照模板提供 Mini Showcase Repository:
这样,我就想确认,在socke.io的plugin里面,对应的this对象,是不是能拿到session,如果不能,我就自己想办法包装一个,我想这个不需要我提供代码吧?
@atian25 也就是说如果session是基础cookie的,那么在controller和middleware 中是无法改变session的是吧。
@liujinyang1994 可以获取的看下我上面发的例子
@ngot 当session使用redis来实现的时候,是取不到的
@liujinyang1994 我也发现了这个问题,的确拿不到,但是可以手动从cookie中取一下。
const session = await app.redis.get(this.cookies.get('EGG_SESS', { encrypt: true }));
console.log(JSON.parse(session));
@Evilcome 我们要不要再开个issue,他们好像没注意到这个问题。
写一个复现的repo,给我调试下
@ngot 我写了一个,尝试注释开 plugin 中的 sessionRedis 设置。
https://github.com/Evilcome/egg-socket-redis-session-demo
测试步骤:
session我在这里做了更多说明
// /app/io/middleware/auth.js
'use strict';
module.exports = app => {
return function* (next) {
// NOTE: 如果用了 session-redis, 这里就拿不到 session 了,
// 如果尝试把 plugin 中 sessionRedis 注释掉,既可以访问到。
// ISSUES: https://github.com/eggjs/egg/issues/1416
if (!this.session.user) {
return this.socket.emit('forbidden');
}
yield* next;
};
};
@Evilcome 赞,我还想晚上写一个来着。
查到原因了:
被 socket.io 接管的请求,都不会进去到 http.createServer(this.callback()); 这个逻辑中去,也就是所有 koa 的中间件都无法执行。
同时,https://github.com/koajs/session/blob/master/index.js#L38 koa-session 是在中间件内部,来处理 session-store 逻辑的。
koa的中间件,目前全部基于 http 模型设计,并且 socket.io 的请求也无法经过 koa 中间件。基于 socket 路径的请求,简单的处理办法是,单独编写中间件。
@atian25 @popomore 有没有好的思路?
cc @fengmk2
感觉要重新设计,不同入口进来,创建 ctx,走相同的流程。只是 ctx 会有差异。
一个走的是http 一个走的是socketio 两者挂载的父级对象是分开的 完全是两个分支 所以你拿不到
但是你可以通过http那部分模型把userid作为变量输出到前端 前端js通过客户端socket api再把userid发送到后端socketio服务来区分用户
这种就属于hack方法了,还是等官方把这个问题修复吧。
@killagu 这个跟你思考的也有点像
不同的协议适配request和response的抽象, 不用改造现有的中间件, 可以使不同的协议都走一套中间件。
protocolConnection.on('req', req => handleProtocolRequest(req))
// 处理某种协议的请求
function handleProtocolRequest(protocolRequest) {
// 将某种协议的请求封装成req, res对象
// 适应koa的`request`和`response`抽象
const { req, res } = protocolReqImpl(req);
// 创建ctx
const ctx = app.createContext(req, res);
// 处理请求, 使用通用的中间件
app.handleRequest(ctx, app.middleware);
}
cc @ngot
两者不应该共享中间件,模型不一样。
socket.io 可以实现一个 session 的中间件,保证两边的通用。其他的还是独立走中间件吧
现在有啥简单的workaround么?按照@Evilcome 提到的从cookie拿EGG_SESS,再从redis拿session,这种方法可以拿到session,但是不好存下去。
要么就不用redis来存session,然后把本来要存到session的东西,直接存到redis,用cookie方式来存session的id?
这个问题现在解决了吗?
这个问题还在解决吗
Most helpful comment
查到原因了:
被 socket.io 接管的请求,都不会进去到
http.createServer(this.callback());这个逻辑中去,也就是所有 koa 的中间件都无法执行。同时,https://github.com/koajs/session/blob/master/index.js#L38 koa-session 是在中间件内部,来处理 session-store 逻辑的。