You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用RedisJSON替代Redis存储express-session并手动访问会话数据?

问题描述

我想跳过req.session.reload()和req.session.save(),直接手动操作express-session的数据,同时用RedisJSON替代原生Redis存储。但遇到两个问题:

  1. express-session默认用Redis的.get()方法存储会话数据,会把数据转成字符串,导致无法用client.json.get()读取
  2. 虽然我能直接调用RedisClient.json的方法,但在express-session的存储逻辑里访问这些方法时,结果是undefined

express-session的核心存储逻辑参考:

defineMethod(Session.prototype, 'save', function save(fn) {
  this.req.sessionStore.set(this.id, this, fn || function(){});
  return this;
});

我的当前配置代码:

const RedisStore = require("connect-redis").default;
const { createClient } = require("redis");
require("dotenv").config();

const RedisClient = createClient({
    url: `redis://localhost:${process.env.REDISPORT}`
});

RedisClient.connect();
const store = new RedisStore({ client: RedisClient });
const RedisJsonGet = RedisClient.json.get.bind(RedisClient.json);
const RedisJsonSet = RedisClient.json.set.bind(RedisClient.json);

const sessionmiddleware = session(
    {
    store: store,
    secret: crypto.randomBytes(32).toString("hex"),
    resave: false,
    saveUninitialized: true
    }
)
解决方案

方案一:自定义RedisStore子类,重写核心方法

通过继承connect-redis的RedisStore,重写get/set/destroy方法,直接调用RedisJSON的命令处理会话数据,从根源上替换存储逻辑。

const RedisStore = require("connect-redis").default;
const { createClient } = require("redis");
const session = require("express-session");
const crypto = require("crypto");
require("dotenv").config();

const RedisClient = createClient({
    url: `redis://localhost:${process.env.REDISPORT}`
});
RedisClient.connect();

// 自定义RedisJSON存储类
class RedisJSONStore extends RedisStore {
  constructor(options) {
    super(options);
    this.client = options.client;
  }

  // 重写set方法:用RedisJSON存储完整JSON对象
  set(id, session, callback) {
    try {
      return this.client.json.set(`sess:${id}`, "$", session)
        .then(() => callback(null))
        .catch(err => callback(err));
    } catch (err) {
      callback(err);
    }
  }

  // 重写get方法:用RedisJSON读取JSON对象
  get(id, callback) {
    try {
      return this.client.json.get(`sess:${id}`)
        .then(session => {
          callback(null, session || null);
        })
        .catch(err => callback(err));
    } catch (err) {
      callback(err);
    }
  }

  // 可选:重写destroy方法,用RedisJSON删除会话
  destroy(id, callback) {
    return this.client.json.del(`sess:${id}`)
      .then(() => callback(null))
      .catch(err => callback(err));
  }
}

// 创建自定义存储实例
const store = new RedisJSONStore({ client: RedisClient });

const sessionmiddleware = session({
  store: store,
  secret: crypto.randomBytes(32).toString("hex"),
  resave: false,
  saveUninitialized: true
});

这样配置后,express-session会自动用RedisJSON存储数据,你可以直接通过RedisClient.json.get("sess:会话ID")手动读取完整的JSON会话对象。

方案二:包装Redis客户端,拦截默认get/set调用

如果不想自定义Store类,可以直接包装Redis客户端的get/set方法,当操作会话前缀(默认是sess:)的键时,自动切换为RedisJSON命令。

const RedisStore = require("connect-redis").default;
const { createClient } = require("redis");
const session = require("express-session");
const crypto = require("crypto");
require("dotenv").config();

const RedisClient = createClient({
    url: `redis://localhost:${process.env.REDISPORT}`
});

// 保存原生方法
const originalGet = RedisClient.get.bind(RedisClient);
const originalSet = RedisClient.set.bind(RedisClient);

// 替换get方法:会话键用RedisJSON读取
RedisClient.get = function(key, ...args) {
  if (key.startsWith("sess:")) {
    return this.json.get(key, ...args);
  }
  return originalGet(key, ...args);
};

// 替换set方法:会话键用RedisJSON存储
RedisClient.set = function(key, value, ...args) {
  if (key.startsWith("sess:")) {
    // 解析express-session传入的序列化字符串为对象
    const sessionObj = typeof value === "string" ? JSON.parse(value) : value;
    return this.json.set(key, "$", sessionObj, ...args);
  }
  return originalSet(key, value, ...args);
};

RedisClient.connect();

const store = new RedisStore({ client: RedisClient });

const sessionmiddleware = session({
  store: store,
  secret: crypto.randomBytes(32).toString("hex"),
  resave: false,
  saveUninitialized: true
});

注意事项

  • 若之前用原生Redis存储过会话,需清空旧数据避免格式冲突
  • 确保Redis服务器已安装RedisJSON模块(推荐使用Redis Stack,或Redis 6.2+手动安装模块)
  • 手动访问会话时,直接调用RedisClient.json.get("sess:你的会话ID")即可获取完整JSON对象

内容的提问来源于stack exchange,提问作者Bobthefishmonger

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 05:25:09