Node.js/Express生产环境会话丢失问题的排查与解决
生产环境Express会话丢失问题修复方案
问题描述
我有一个部署在Hetzner的Debian Linux服务器上的Node.js/Express.js站点,采用Nginx/pm2运行。登录时req.session.user能正常设置为admin,但后续浏览器检查用户时会话丢失,本地开发环境运行正常,生产环境存在该问题。
以下是我的server.ts会话及Cookie配置代码:
import * as model from './model.js'; import express from 'express'; import cors from 'cors'; import * as config from './config.js'; import { INewBook } from './interfaces.js'; import session from 'express-session'; import cookieParser from 'cookie-parser'; declare module 'express-session' { export interface SessionData { user: { [key: string]: any }; } } const app = express(); app.use(express.json()); app.use(cors({ origin: config.FRONTEND_URL, methods: ['POST', 'GET', 'DELETE', 'PUT', 'OPTIONS', 'HEAD'], credentials: true })); app.set('trust proxy', 1); app.use(cookieParser()); app.use( session({ resave: true, saveUninitialized: true, secret: config.SESSION_SECRET, cookie: { httpOnly: true, sameSite: config.NODE_ENVIRONMENT === 'production' ? 'none' : 'lax', secure: config.NODE_ENVIRONMENT === 'production' } }) ); app.all('/', function (req, res, next) { res.header("Access-Control-Allow-Origin", "https://et-mern-crud-site.tanguay.eu"); res.header("Access-Control-Allow-Headers", "X-Requested-With"); next(); });
关键修复点
1. 替换默认内存会话存储
express-session默认使用内存存储会话,生产环境下pm2多进程、服务器重启都会导致会话全部丢失,必须替换为持久化存储方案,比如Redis或MongoDB。
示例(使用Redis存储):
首先安装依赖:
npm install connect-redis redis
修改session配置:
import { createClient } from 'redis'; import RedisStore from 'connect-redis'; // 初始化Redis客户端 const redisClient = createClient({ url: 'redis://localhost:6379' // 根据你的Redis实例地址调整 }); redisClient.connect().catch(console.error); // 更新session配置,使用Redis存储 app.use( session({ resave: false, // 建议设为false,减少不必要的存储操作 saveUninitialized: false, // 只保存已初始化的会话,避免空会话占用存储 secret: config.SESSION_SECRET, store: new RedisStore({ client: redisClient }), cookie: { httpOnly: true, sameSite: config.NODE_ENVIRONMENT === 'production' ? 'none' : 'lax', secure: config.NODE_ENVIRONMENT === 'production', maxAge: 24 * 60 * 60 * 1000, // 可选:设置会话过期时间,比如1天 domain: '.tanguay.eu' // 匹配前端根域名,确保子域名下能共享Cookie } }) );
2. 统一CORS配置,消除冲突
当前代码同时使用cors中间件和手动设置CORS头,容易导致头信息冲突。保留cors中间件即可,删除手动设置的CORS代码:
// 删除这段代码 app.all('/', function (req, res, next) { res.header("Access-Control-Allow-Origin", "https://et-mern-crud-site.tanguay.eu"); res.header("Access-Control-Allow-Headers", "X-Requested-With"); next(); });
确保config.FRONTEND_URL的值与前端实际访问URL完全一致(比如https://et-mern-crud-site.tanguay.eu)。
3. 修正Nginx代理配置
Nginx需要正确传递协议、主机等头信息,确保会话Cookie的secure属性生效。在Nginx配置中添加以下内容:
location / { proxy_pass http://localhost:3000; # 替换为你的Node服务端口 proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # 关键:传递当前请求协议(http/https) proxy_cache_bypass $http_upgrade; }
4. 确认环境变量设置
确保生产环境中NODE_ENVIRONMENT被正确设置为production,可以通过pm2启动命令指定:
pm2 start app.js --env production
或者在服务器环境变量中全局设置:
export NODE_ENVIRONMENT=production
内容的提问来源于stack exchange,提问作者Edward Tanguay
相关产品推荐
相关产品推荐

