Node系列 · Express:session
2026/9/4 6:55:13 网站建设 项目流程

Node系列 · Express:session

Session 是传统服务端会话方案——登录后服务端存一份"会话状态",客户端只持有 sessionId。本章对比 Cookie 与 Session、Express 用 express-session 实现登录态管理。

一、Cookie vs Session

Session 方案

服务端存完整数据
客户端只持 sessionId

Cookie 方案

所有数据都存客户端
不安全的明文

维度CookieSession
数据存储客户端服务端
容量4KB无限制(看存储后端)
安全性数据暴露在客户端数据在服务端,客户端只有 ID
实现复杂度简单需要 session 存储
服务端扩展无状态(多实例无障碍)多实例需要共享 session 存储
适用不敏感数据、会话标识登录态、用户偏好

::: tip
登录态首选 Session——密码、用户信息等敏感数据不能放 Cookie。Session 的 ID 只是个随机字符串,泄露后服务端可主动失效。
:::

二、express-session 基础

npminstallexpress-session
const 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.2resavesaveUninitialized

选项推荐说明
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-redis
const 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-sequelize
const 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 登录后 regenerate

app.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 配置httpOnly+secure(生产)+sameSite: 'lax'
secret随机长字符串,存环境变量
多实例必须用 Redis 等共享存储

八、与 JWT 的取舍

维度SessionJWT
数据存储服务端客户端(payload)
多实例需要共享存储无状态,天然支持
主动失效✅(服务端删 session)❌(要等过期或拉黑名单)
实现较重
适用传统 Web 应用前后端分离 / 移动端 / 微服务

::: tip
传统 Web 用 Session——后台能主动踢人(封号、改密)。API / 移动端 / 微服务用 JWT——天然无状态、跨域友好。详见 JWT 章节。
:::

九、小结

  • Session 把数据存服务端,客户端只持 sessionId——比 Cookie 安全
  • express-session是标准中间件;生产用 Redis 存储支持多实例
  • 关键配置:secret(签名密钥)+resave: false+saveUninitialized: false+ Cookie 安全属性
  • 登录后regeneratesessionId 防会话固定;退出destroy()+clearCookie()
  • 多实例部署必须用共享存储(Redis / 数据库),不能用默认内存
  • Session 与 JWT:传统 Web 用 Session,API/移动端用 JWT

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询