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

Nest.js中express-session的Set-Cookie头失效——跨域问题

跨域场景下express-session Set-Cookie头丢失及Cookie无法接收问题解决

针对跨域部署后Set-Cookie头不显示、生产环境无法接收Cookie的问题,核心原因是Cookie配置不完整,加上CORS和HTTPS环境的细节未处理到位,以下是具体修复步骤:

1. 补全Cookie的关键配置项

当前代码缺少sameSite属性,跨域场景下必须将其设为none,同时配合secure: true,还要补充domain和path确保Cookie能被前端正确接收:

cookie: {
  maxAge: 3600000, // 注意:原配置360000是10分钟,1小时需改为3600*1000=3600000
  secure: process.env.NODE_ENV !== 'production' ? false : true,
  sameSite: process.env.NODE_ENV !== 'production' ? 'lax' : 'none', // 跨域必须设为none
  domain: '.your-domain.com', // 替换为前后端共享的父域,比如前端是app.your-domain.com、后端是api.your-domain.com
  path: '/', // 确保全站路径都能访问Cookie
  httpOnly: true, // 可选,增强Cookie安全性,防止XSS攻击
}
  • sameSite: none是跨域Cookie传递的必要条件,必须和secure: true同时启用
  • domain需设置为前端域名的父域,确保Cookie能被前端所在域读取;若前后端为完全不同的顶级域,建议改用Token认证方案
  • 修正maxAge数值错误,避免Session提前过期

2. 修正CORS配置的Origin问题

当前CORS的origin数组包含带斜杠的域名,这是无效的,CORS Origin必须是精确的纯域名(不带路径):

app.enableCors({
  origin: frontDomain, // 仅保留纯域名,例如"https://front.example.com"
  credentials: true,
  allowedHeaders: ['Content-Type', 'Authorization'], // 明确允许必要的请求头
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], // 覆盖常见请求方法
});

Origin不匹配会导致浏览器拒绝接收Cookie,必须确保此处域名与前端实际访问的域名完全一致。

3. 适配生产环境的HTTPS反向代理

若生产环境后端通过Nginx等反向代理提供服务,需确保代理传递HTTPS协议标识,否则express会认为当前是HTTP环境,忽略secure: true的Cookie设置:

  • 在Nginx配置中添加:
    proxy_set_header X-Forwarded-Proto $scheme;
    
  • 在NestJS中信任代理:
    app.set('trust proxy', true); // 在bootstrap函数开头添加
    

该步骤能让express正确识别请求协议,确保Set-Cookie头正常输出。

4. 检查Session初始化逻辑

当前saveUninitialized: false意味着只有当Session被修改时(例如req.session.user = xxx)才会发送Set-Cookie头。若首次请求需要设置Cookie,可临时将其改为true,但注意这会产生未使用的Session记录,建议根据业务场景调整。

完整修改后的main.ts代码示例

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule);
  // 信任反向代理,适配HTTPS环境
  app.set('trust proxy', true);
  
  const sessionSecret = app.get(AppConfigService).getConfig().session.secret;
  const frontDomain = app.get(AppConfigService).getConfig().front.domain;
  const port = app.get(AppConfigService).getConfig().app.port;

  app.setGlobalPrefix('api');

  app.use(
    session({
      name: 's.id',
      secret: sessionSecret,
      resave: false,
      saveUninitialized: false, // 根据业务需求调整为true或false
      cookie: {
        maxAge: 3600000, // 修正为1小时
        secure: process.env.NODE_ENV !== 'production' ? false : true,
        sameSite: process.env.NODE_ENV !== 'production' ? 'lax' : 'none',
        domain: '.your-domain.com', // 替换为实际的父域名
        path: '/',
        httpOnly: true,
      },
      store: new PrismaSessionStore(new PrismaClient(), {
        checkPeriod: 2 * 60 * 1000, //ms
        dbRecordIdIsSessionId: true,
        dbRecordIdFunction: undefined,
      }),
    }),
  );
  app.enableCors({
    origin: frontDomain,
    credentials: true,
    allowedHeaders: ['Content-Type', 'Authorization'],
    methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
  });
  app.use(passport.initialize());
  app.use(passport.session());
  await app.listen(port);
}
bootstrap();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 01:20:19