session取值为空,但sessionStore内是有值。这是为什么???
发布于 9 年前 作者 mrlong 7527 次浏览 最后一次编辑是 8 年前 来自 问答

见图:

捕获.PNG

SessionStore 对象内有openid 的值,但是session 内是空的。为什么???

11 回复

首先保证变量获取正确,然后帮顶!

我在做一个网站微信二维扫一扫登录功能: 1. 进入网站,判定session (我暂定为A) 有没有值,如有值是直接进入主页。 2. 如session (A) 没有值则调用api 生成临时二维码,并给id值=10000. 将img 图转到页面用户扫。 3. 用户扫了之后会有事件,取出openid 校对成功之后我向req.session 写openid ,这时的session (我暂定为B),同时也写了wxsession 。

问题出现了: session (A) 、session (B) wxsession 三个保存sessionStore 都不一样。 我回到网站时无法取出openid 的值。

捕获1.PNG

第二步生产二维码带上sessionA的sid, 再由微信登录callback回来,把一个已登录的状态写在内存里(或其他存储媒介,随便), 展示二维码那个页面,肯定是一个轮询啊,不断向上述那个媒介查询自己的sid是否已经设置为已登录, 如果取得到,就处理登录逻辑, 这样说能明白吗?

@captainblue2013 谢谢。 你的方案是放弃session 采用外部存储,可行性是可以,但比直接用session 复杂。 不是好最发解决之道。

@mrlong 那是因为你还没真正明白session是什么

@captainblue2013 那请问下,你明白的session又是怎样的?session不就是标识一个人,然后将人的信息保存在服务端,以便下一次识别。除了这,session还有很高大上的含义么?

@mrlong 你需要注意的是,express使用的session是每一次http请求都会生成1个新的sessionid的,所以你每次读取的话都是新的sessionid对应的值。你可以读一读express-session对session生成的机制。只有在你的请求cookie(request cookie)有带入connect.sid,才不会生成新的sessionid。这个时候你拿到的sessionid才是requestcookie里面的的sessionid。

@hinson0 谢谢你的回复。

  1. express 内的session 机制 express-session 已处理掉,不是我的问题所在,并我已测试过如不用 微信扫回调机制session 是没有问题,并校对过req.sessionID是对的。

  2. 微信扫一扫回调事件之后我的req.sessionID 已发变化了。在图示就能看出。 问过 node-wechat api 的作者,其建议我用oauth。我就不明白是无法更正的问题还是存在的bug。

@mrlong 我现在的做法是,依然使用session,但是不使用express-session。将sessionid以login接口的值传入给前端,前端会在浏览器的Localstorage出保存起来。我之前也考虑oauth2。不过因为是自己做,oauth2相对而言,是一种“授权”,所以就还是使用session了。

帖段我的代码:

// 依赖
var moment = require('moment');
var async = require('async');
var uid = require('uid-safe').sync;

var redis = require('../library/redis').create();

// UserService
var UserService = {
  setSession: function (user, req) {
    var sid = uid(24);
    var expired = moment().unix() + 7 * 24 * 60 * 60;
    var session = {
      id: sid,
      expired: expired,
      user: user.get({plain: true}),
      user_id: user.id
    };
    var stringify = JSON.stringify(session);
    redis.set(sid, stringify);
    req.session = session;
    req.user = user;
  },
  destroySession: function (req) {
    redis.expire(req.session.id, 0);
  },
  checkSession: function (req, res, next) {
    async.waterfall([
      // get session id
      function (cb) {
        var sid = req.query.sid;
        if (!sid) {
          cb('请登录后访问');
        } else {
          cb(null, sid);
        }
      },
      // get session
      function (sid, cb) {
        redis.get(sid, function (err, session) {
          if (session) {
            cb(null, session);
          } else {
            console.log('session empty, sid ' + sid);
            cb('请登录后访问');
          }
        });
      },
      // check whether session expired or not
      function (session, cb) {
        var parsed = JSON.parse(session);
        if (parsed.expired <= moment().unix()) {
          console.log('session expired, sid ' + session.id);
          cb('请重新登录后访问');
        } else {
          cb(null, parsed);
        }
      },
    ], function (err, session) {
      if (err) {
        res.status(403);
        res.json({msg: err});
      } else {
        console.log('userid ' + session.user_id + ' session check success');
        next();
      }
    });
  },
  isMe: function (req, userId) { // 是否为自己
    var me = req.session.user_id;
    return parseInt(me) === parseInt(userId);
  }
};

module.exports = UserService;

setSession方法是在login出调用,destroySession是在logout出,而checkSession则是在需要校验session的接口处调用

@mrlong 因为通过微信的事件回调后,request cookie是无法跟着ajax一直走的,因此在回调的requestcookie中没有带入connect.sid,因此你的req.sessionid就是新的值。我也是因为这个问题,才换了一种思维,让前端在localstorage中存sessionid,而不是用cookie。

@hinson0 谢谢你及时回复。

  1. 从你的代码中我明白了,pc 采用扫一扫微信登录,是涉及到两个端 一个是pc浏览器,及微信端。 按原理 必然会生成两个不同的sessionID。

  2. 唯一的交点就是pc生成的二维码怎么与微信端扫后关联起来。 我查了node-wechat 的api 生成临时的qrcode 只有保存 场景id (int 型) 不是string , 无将sessionID 转到微信端。 ’’'js /**

  • 创建临时二维码
  • 详细请看:http://mp.weixin.qq.com/wiki/index.php?title=生成带参数的二维码
  • Examples:
  • api.createTmpQRCode(10000, 1800, callback);
  • Callback:
    • err, 调用失败时得到的异常
    • result, 调用正常时得到的对象
  • Result:
  • {
  • “ticket”:“gQG28DoAAAAAAAAAASxodHRwOi8vd2VpeGluLnFxLmNvbS9xL0FuWC1DNmZuVEhvMVp4NDNMRnNRAAIEesLvUQMECAcAAA==”,
  • “expire_seconds”:1800
  • }
  • @param {Number} sceneId 场景ID
  • @param {Number} expire 过期时间,单位秒。最大不超过1800
  • @param {Function} callback 回调函数 */ exports.createTmpQRCode = function (sceneId, expire, callback) { this.preRequest(this._createTmpQRCode, arguments); }; ’’’
回到顶部