New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

io.controller和io.middleware的context都无法获取到session #1416

Closed
wrightjin opened this Issue Sep 12, 2017 · 30 comments

Comments

Projects
None yet
@wrightjin

wrightjin commented Sep 12, 2017

  • Node Version: 7.10.0
  • Egg Version: 1.7.0
  • Plugin Name: egg-socket.io
  • Plugin Version: 2.1.0
  • Platform: Windows
  • Mini Showcase Repository:

io.controller和io.middleware都无法获取到session,但app.controller中可以获取,请问是什么原因?

@atian25

This comment has been minimized.

Member

atian25 commented Sep 12, 2017

socket.io 和 http 不是一个模型来着

@wrightjin

This comment has been minimized.

wrightjin commented Sep 12, 2017

那我需要怎么做才可以拿到session呢?

@ngot

This comment has been minimized.

Member

ngot commented Sep 12, 2017

请提供复现代码

@wrightjin

This comment has been minimized.

wrightjin commented Sep 12, 2017

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的内容

@ngot

This comment has been minimized.

Member

ngot commented Sep 12, 2017

这样看不出什么来。请按照模板提供 Mini Showcase Repository:

@wrightjin

This comment has been minimized.

wrightjin commented Sep 13, 2017

这样,我就想确认,在socke.io的plugin里面,对应的this对象,是不是能拿到session,如果不能,我就自己想办法包装一个,我想这个不需要我提供代码吧?

@jinyang1994

This comment has been minimized.

jinyang1994 commented Sep 14, 2017

@atian25 也就是说如果session是基础cookie的,那么在controller和middleware 中是无法改变session的是吧。

@ngot

This comment has been minimized.

Member

ngot commented Sep 15, 2017

@liujinyang1994 可以获取的看下我上面发的例子

@ngot ngot closed this Oct 1, 2017

@jinyang1994

This comment has been minimized.

jinyang1994 commented Oct 9, 2017

@ngot 当session使用redis来实现的时候,是取不到的

@Evilcome

This comment has been minimized.

Evilcome commented Oct 11, 2017

@liujinyang1994 我也发现了这个问题,的确拿不到,但是可以手动从cookie中取一下。

const session = await app.redis.get(this.cookies.get('EGG_SESS', { encrypt: true }));
console.log(JSON.parse(session));  
@jinyang1994

This comment has been minimized.

jinyang1994 commented Oct 12, 2017

@Evilcome 我们要不要再开个issue,他们好像没注意到这个问题。

@ngot

This comment has been minimized.

Member

ngot commented Oct 12, 2017

写一个复现的repo,给我调试下

@Evilcome

This comment has been minimized.

Evilcome commented Oct 12, 2017

@ngot 我写了一个,尝试注释开 plugin 中的 sessionRedis 设置。

https://github.com/Evilcome/egg-socket-redis-session-demo

测试步骤:

  1. 访问 http://127.0.0.1:7001/ 保存 session
  2. 访问 http://127.0.0.1:7001/public/socket-client.html 来测试链接。

我在这里做了更多说明
// /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;
  };
};
@jinyang1994

This comment has been minimized.

jinyang1994 commented Oct 12, 2017

@Evilcome 赞,我还想晚上写一个来着。

@ngot

This comment has been minimized.

Member

ngot commented Oct 13, 2017

查到原因了:

被 socket.io 接管的请求,都不会进去到 http.createServer(this.callback()); 这个逻辑中去,也就是所有 koa 的中间件都无法执行。

同时,https://github.com/koajs/session/blob/master/index.js#L38 koa-session 是在中间件内部,来处理 session-store 逻辑的。

@ngot

This comment has been minimized.

Member

ngot commented Oct 13, 2017

koa的中间件,目前全部基于 http 模型设计,并且 socket.io 的请求也无法经过 koa 中间件。基于 socket 路径的请求,简单的处理办法是,单独编写中间件。

@atian25 @popomore 有没有好的思路?

@atian25

This comment has been minimized.

Member

atian25 commented Oct 13, 2017

@popomore

This comment has been minimized.

Member

popomore commented Oct 13, 2017

感觉要重新设计,不同入口进来,创建 ctx,走相同的流程。只是 ctx 会有差异。

@phper-chen

This comment has been minimized.

phper-chen commented Nov 14, 2017

一个走的是http 一个走的是socketio 两者挂载的父级对象是分开的 完全是两个分支 所以你拿不到
但是你可以通过http那部分模型把userid作为变量输出到前端 前端js通过客户端socket api再把userid发送到后端socketio服务来区分用户

@jinyang1994

This comment has been minimized.

jinyang1994 commented Nov 14, 2017

这种就属于hack方法了,还是等官方把这个问题修复吧。

@popomore

This comment has been minimized.

Member

popomore commented May 17, 2018

@killagu 这个跟你思考的也有点像

@killagu

This comment has been minimized.

Contributor

killagu commented May 18, 2018

简单的思路

不同的协议适配requestresponse的抽象, 不用改造现有的中间件, 可以使不同的协议都走一套中间件。

附上一些伪代码

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

This comment has been minimized.

Member

atian25 commented May 18, 2018

cc @ngot

@dead-horse

This comment has been minimized.

Member

dead-horse commented May 23, 2018

两者不应该共享中间件,模型不一样。

socket.io 可以实现一个 session 的中间件,保证两边的通用。其他的还是独立走中间件吧

@kchjxxgh

This comment has been minimized.

kchjxxgh commented May 24, 2018

现在有啥简单的workaround么?按照@Evilcome 提到的从cookie拿EGG_SESS,再从redis拿session,这种方法可以拿到session,但是不好存下去。
要么就不用redis来存session,然后把本来要存到session的东西,直接存到redis,用cookie方式来存session的id?

@T--T

This comment has been minimized.

T--T commented Jul 8, 2018

这个问题现在解决了吗?

@Aysnine

This comment has been minimized.

Aysnine commented Aug 5, 2018

这个问题还在解决吗

@ngot

This comment has been minimized.

Member

ngot commented Sep 29, 2018

@ngot

This comment has been minimized.

Member

ngot commented Sep 29, 2018

  • egg-socket.io@4.1.4

@ngot ngot closed this Sep 29, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment