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

Express.js每次请求创建多会话问题排查求助

解决Express微服务跨域会话疯狂创建的问题

看起来你遇到的核心问题是跨域场景下会话Cookie没有被正确识别,导致每次前端请求都触发新会话创建,结合你的配置和现象,我给你梳理几个排查方向和修复步骤:

一、先确认前端请求的Cookie携带逻辑

虽然你提到没发现请求不带Cookie,但跨域场景下浏览器的Cookie携带是有严格限制的,先检查这几个关键点:

  • 前端必须显式开启跨域携带Cookie:
    如果你用Axios,要在请求里加withCredentials: true:

    axios.post('你的GraphQL接口地址', query, { withCredentials: true })
    

    用Fetch的话,要设置credentials: 'include':

    fetch('你的GraphQL接口地址', {
      method: 'POST',
      credentials: 'include',
      body: JSON.stringify(query)
    })
    

    打开浏览器开发者工具的Network面板,查看每个GraphQL请求和OPTIONS预检请求的Request Headers,确认是否存在Cookie字段,且携带的会话ID和Redis里的初始会话ID一致。

  • Cookie的跨域配置是否匹配:
    本地开发环境下(HTTP协议):

    • sameSite要设为lax(不能是strict,否则跨域跳转后Cookie不会被携带)
    • secure必须设为false(HTTP环境下secure: true的Cookie会被浏览器忽略)
    • domain设为localhost(如果前后端都是localhost不同端口的话)
      生产环境HTTPS下,如果是跨域名部署,sameSite要设为none,同时secure: true,domain设为根域名(比如.example.com)实现子域名共享。

二、排查会话配置的潜在问题

你的会话配置里有几个可能的风险点:

  • disableTTL: true是隐患:
    这个配置会让Redis里的会话永久存在,即使找到问题根源,之前的无效会话也会一直占用空间。建议先去掉这个配置,设置和cookie.maxAge一致的TTL,让Redis自动清理过期会话:

    const sessionOptions = {
      store: new RedisStore({ 
        client: redisClient, 
        ttl: toTime(config.cookie.maxAge).ms() / 1000, // 转成秒单位
      }),
      // 其他配置不变
    };
    
  • 确保OPTIONS预检请求不触发会话创建:
    虽然你设置了saveUninitialized: false,但某些中间件(比如Passport的钩子)可能会无意中修改会话对象,导致空会话被保存到Redis。可以在会话中间件之前加一个过滤逻辑,跳过OPTIONS请求的会话处理:

    // 先处理OPTIONS请求,再初始化会话
    app.use((req, res, next) => {
      if (req.method === 'OPTIONS') {
        return next();
      }
      session(sessionOptions)(req, res, next);
    });
    // 再初始化Passport
    app.use(passport.initialize());
    app.use(passport.session());
    

三、关于自定义genid的奇怪现象

你给认证服务设置的genid逻辑(无username时返回null)本身就不符合express-session的要求——genid必须返回有效的会话ID字符串,返回null会导致会话无法正常创建,自然触发CSRF异常。而登录成功后只生成一个会话,是因为此时username存在,生成了固定前缀的会话ID,前端请求恰好携带了这个Cookie,属于歪打正着,不是正确的解决方案,建议恢复默认的genid逻辑。

四、验证修复的步骤

  1. 清空Redis所有会话:执行FLUSHALL命令
  2. 重启所有微服务
  3. 登录后检查Redis,确认只有1个会话
  4. 跳转到React前端,发起GraphQL请求,观察会话数量是否保持不变
  5. 点击页面链接,确认会话数量不再持续增加

如果还是有问题,建议用浏览器Application面板查看Cookie的属性,确认domain、sameSite、secure是否和配置一致,再逐一排查Passport的serializeUser/deserializeUser逻辑,看是否存在每次请求都修改会话对象的情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:05:01