
Node系列 · ExpresssessionSession 是传统服务端会话方案——登录后服务端存一份会话状态客户端只持有 sessionId。本章对比 Cookie 与 Session、Express 用 express-session 实现登录态管理。一、Cookie vs SessionSession 方案服务端存完整数据客户端只持 sessionIdCookie 方案所有数据都存客户端不安全的明文维度CookieSession数据存储客户端服务端容量4KB无限制看存储后端安全性数据暴露在客户端数据在服务端客户端只有 ID实现复杂度简单需要 session 存储服务端扩展无状态多实例无障碍多实例需要共享 session 存储适用不敏感数据、会话标识登录态、用户偏好::: tip登录态首选 Session——密码、用户信息等敏感数据不能放 Cookie。Session 的 ID 只是个随机字符串泄露后服务端可主动失效。:::二、express-session 基础npminstallexpress-sessionconst session require(express-session); app.use(session({ secret: keyboard cat, // 签名密钥必填生产用随机字符串 resave: false, // 强制重新保存即使未修改 saveUninitialized: false, // 强制保存空 session cookie: { httpOnly: true, // 防 XSS secure: true, // 仅 HTTPS生产 sameSite: lax, // 防 CSRF maxAge: 24 * 60 * 60 * 1000, // 24 小时 }, })); // 使用 app.post(/api/login, (req, res) { req.session.userId user.id; // 存 session res.json({ user }); }); app.get(/api/profile, (req, res) { if (!req.session.userId) { return res.status(401).json({ error: 未登录 }); } // ... });三、关键配置项3.1secret用于签名 sessionId防篡改// 生产环境随机长字符串 app.use(session({ secret: process.env.SESSION_SECRET || require(crypto).randomBytes(32).toString(hex), }));3.2resave与saveUninitialized选项推荐说明resavefalse请求未修改 session 时不重写存储——性能更好saveUninitializedfalse不保存空 session——避免无意义的存储写入3.3cookie选项完整配置cookie: { httpOnly: true, // 防 XSS secure: process.env.NODE_ENV production, // 仅 HTTPS生产 sameSite: lax, // 防 CSRF maxAge: 24 * 60 * 60 * 1000, // 24 毫秒单位 domain: .example.com, // 子域共享可选 path: /, // 路径 }3.4 滚动会话rolling: true让 session 在每次请求时自动续期——活跃用户不会突然过期app.use(session({ rolling: true, cookie: { maxAge: 60 * 60 * 1000 }, // 每次请求重置 1 小时 }));::: warning滚动会话有安全权衡活跃用户一直不过期但 token 长期有效——被盗后攻击者能长期使用。需要结合 IP / User-Agent 检测。:::四、session 存储后端默认express-session把 session 存在内存——多实例部署会失效每个进程一份内存。4.1 内存存储默认// 不指定 store 就是内存存储 app.use(session({ secret: xxx }));适用单实例开发。生产禁用——重启丢所有 session。4.2 Redis 存储生产首选npminstallredis connect-redisconst session require(express-session); const RedisStore require(connect-redis).default; const { createClient } require(redis); const redisClient createClient({ url: redis://127.0.0.1:6379 }); await redisClient.connect(); app.use(session({ store: new RedisStore({ client: redisClient }), secret: xxx, resave: false, saveUninitialized: false, cookie: { maxAge: 24 * 60 * 60 * 1000 }, }));Redis 优势多实例共享 session任意 Node 进程都能读到同一份 session自动过期Redis TTL重启不丢数据4.3 数据库存储npminstallconnect-session-sequelizeconst session require(express-session); const SequelizeStore require(connect-session-sequelize)(session.Store); const { sequelize } require(./models); app.use(session({ store: new SequelizeStore({ db: sequelize }), secret: xxx, resave: false, saveUninitialized: false, }));会自动创建Sessions表——MySQL/PostgreSQL 都能用。五、session 操作 API// 存 req.session.userId 1; req.session.cart [1, 2, 3]; // 读 const userId req.session.userId; // 重新生成 sessionId防会话固定 req.session.regenerate((err) { req.session.userId userId; }); // 销毁 session退出登录 req.session.destroy((err) { res.clearCookie(connect.sid); res.json({ ok: true }); }); // 重新加载 session多步操作时 req.session.reload((err) { console.log(req.session); });5.1 登录后 regenerateapp.post(/login, async (req, res) { // 1. 验证用户 const user await authenticate(req.body); // 2. 登录成功重新生成 sessionId防会话固定 req.session.regenerate((err) { if (err) return next(err); req.session.userId user.id; req.session.save((err) { res.json({ user }); }); }); });::: tip登录后regeneratesessionId 是安全最佳实践——防止会话固定攻击攻击者预先设一个 sessionId 让受害者用登录后劫持会话。:::六、退出登录app.post(/api/logout, (req, res) { req.session.destroy((err) { if (err) return next(err); res.clearCookie(connect.sid); // 清除 session cookie res.json({ ok: true }); }); });七、最佳实践场景推荐开发环境默认内存存储即可生产环境Redis 存储多实例共享 自动过期登录后req.session.regenerate()防会话固定退出req.session.destroy()res.clearCookie()Cookie 配置httpOnlysecure生产sameSite: laxsecret随机长字符串存环境变量多实例必须用 Redis 等共享存储八、与 JWT 的取舍维度SessionJWT数据存储服务端客户端payload多实例需要共享存储无状态天然支持主动失效✅服务端删 session❌要等过期或拉黑名单实现较重轻适用传统 Web 应用前后端分离 / 移动端 / 微服务::: tip传统 Web 用 Session——后台能主动踢人封号、改密。API / 移动端 / 微服务用 JWT——天然无状态、跨域友好。详见 JWT 章节。:::九、小结Session 把数据存服务端客户端只持 sessionId——比 Cookie 安全express-session是标准中间件生产用 Redis 存储支持多实例关键配置secret签名密钥resave: falsesaveUninitialized: false Cookie 安全属性登录后regeneratesessionId 防会话固定退出destroy()clearCookie()多实例部署必须用共享存储Redis / 数据库不能用默认内存Session 与 JWT传统 Web 用 SessionAPI/移动端用 JWT