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

express-session无法读取跨服务传递的会话Cookie问题排查

问题场景与现象

本地同时运行两个服务:

  • 3300端口:SSR Vite Vue应用
  • 4400端口:json-server托管模拟Web API的db.json

基于express-session实现登录认证逻辑:

  • 登录时将用户信息存入req.session并调用req.session.save()
  • 通过/me接口获取当前会话用户
  • SSR服务的auth中间件会将浏览器Cookie转发到json-server的/me接口

问题现象:

  • Postman直接请求/login和/me功能正常,能正确返回用户信息
  • SSR转发Cookie到/me时,尽管req.headers.cookie包含connect.sid,但req.session中仅存在cookie配置,无user属性:
    Session {
      cookie: {
        path: '/',
        _expires: null,
        originalMaxAge: null,
        httpOnly: true,
        sameSite: false
      }
    }
    

核心代码片段

JSON Server 主文件

import bodyParser from 'body-parser';
import cors from 'cors';
import dotenv from 'dotenv';
import express from 'express';
import jsonServer from 'json-server';

import mockLogin from './mocked-auth/login.handler.js';
import mockLogout from './mocked-auth/logout.handler.js';
import me from './mocked-auth/me.handler.js';
import { expressCookieSession } from './mocked-auth/session.middleware.js';

dotenv.config();

const server = jsonServer.create();
const router = jsonServer.router('./json-server/db.json');
const middlewares = jsonServer.defaults();

server.use(cors());

// 原代码:使用子app挂载auth路由和session中间件
const app = express();
app.use(expressCookieSession);
app.use(bodyParser.json());
mockLogin(app, router);
mockLogout(app);
me(app);
server.use(app); 

server.use(middlewares);
server.use(router);

const port = process.env.JSON_SERVER_PORT;

server.listen(port, () => {
  console.log('\x1b[32m%s\x1b[0m', `JSON Server is running at http://localhost:${port}/`);
});

SSR Auth 中间件

import { RequestHandler } from 'express';
import { ofetch } from 'ofetch';

const auth: RequestHandler = async (req, res, next) => {
  console.log('SSR Entrypoing, AUTH', req.headers.cookie);

  const user = await ofetch('http://localhost:4400/me', {
    method: 'get',
    headers: {
      cookie: req.headers.cookie as any,
    },
    credentials: 'include',
  }).catch(err => {
    console.log(err, '\njson-server has not found user from req.session');
  });
  if (!user) return next();
  req.user = user;

  next();
};

export default auth;

问题排查与解决方案

1. 调整 express-session 中间件挂载范围与顺序

原代码将session中间件挂载在子app上,仅作用于该子app的路由,可能导致会话解析逻辑不统一。同时中间件顺序不合理,会影响会话解析优先级。

修改方案:
直接将session中间件挂载到主server实例,确保所有请求都经过会话解析,同时调整中间件顺序(session优先于cors、bodyParser):

dotenv.config();

const server = jsonServer.create();
const router = jsonServer.router('./json-server/db.json');
const middlewares = jsonServer.defaults();

// 1. 优先挂载session中间件,确保所有请求都经过会话解析
server.use(expressCookieSession);
// 2. 配置带credentials的CORS,限制可信源
const corsOptions = {
  origin: `http://localhost:${process.env.VITE_SSR_PORT || 3300}`,
  credentials: true,
};
server.use(cors(corsOptions));
// 3. 挂载body解析中间件
server.use(bodyParser.json());

// 4. 直接在主server上挂载auth路由,无需子app
mockLogin(server, router);
mockLogout(server);
me(server);

// 5. 最后挂载json-server默认中间件与路由
server.use(middlewares);
server.use(router);

服务器端使用ofetch时,credentials: 'include'是冗余配置(仅浏览器环境需要),且可能与手动设置的cookie头冲突,导致Cookie传递异常。

修改方案:
移除credentials配置,仅保留手动传递的cookie头:

const auth: RequestHandler = async (req, res, next) => {
  console.log('SSR Entrypoing, AUTH', req.headers.cookie);

  const user = await ofetch('http://localhost:4400/me', {
    method: 'get',
    headers: {
      cookie: req.headers.cookie as string,
    },
    // 移除 credentials: 'include'
  }).catch(err => {
    console.log(err, '\njson-server 未从 req.session 找到用户');
  });
  if (!user) return next();
  req.user = user;

  next();
};

sameSite: false在部分跨域场景下可能存在兼容问题,建议改为lax;同时设置明确的会话过期时间,避免会话无期限存在:

// mocked-auth/session.middleware.js
const sessionConfig = {
  secret: 'your_secret_key',
  resave: false,
  saveUninitialized: true,
  cookie: {
    httpOnly: true,
    sameSite: 'lax', // 提升跨域场景兼容性
    maxAge: 24 * 60 * 60 * 1000, // 设置24小时会话过期时间
  },
};

验证步骤

  1. 重启json-server和SSR服务
  2. 登录后触发SSR页面请求,检查/me接口的req.session是否包含user属性
  3. 确认SSR服务能正确获取用户信息

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 07:29:52