关于Express Session中间件会话重分配的技术疑问
关于Express Session会话重分配的问题解答
1. 重复会话该怎么处理?要不要销毁新会话绑定旧的?
最好这么做——销毁新会话并把原有会话绑定到当前请求,不然数据库里确实会堆一堆没用的会话占空间。具体操作可以这么来:
- 用户登录时,先查数据库里这个用户有没有关联的有效会话ID
- 如果有:
- 调用
req.session.destroy()干掉当前新创建的会话 - 把
req.sessionID改成原来的会话ID,把旧会话绑到当前请求上 - 调用
req.session.reload()把旧会话的数据重新加载到请求对象里
- 调用
- 另外记得给会话设个合理的过期时间(比如用
cookie.maxAge配置),再配合存储端的自动清理机制,能进一步减少无效会话堆积。
2. 为啥Express Session一有请求就立刻创建新会话?
这是默认配置的锅——默认resave和saveUninitialized都是true。
saveUninitialized: true会强制把没初始化的空会话(刚创建、还没写任何用户数据的那种)存到数据库里- 本来是为了方便追踪所有访客,哪怕是没登录的匿名用户,比如统计访客数、做匿名购物车这类功能
- 要是不想给匿名请求创建会话,把
saveUninitialized改成false就行,这样只有当你主动往req.session里写数据的时候,会话才会被创建并保存。
3. 会话重分配需要啥条件?具体咋实现?
要不要登录或密钥?
会话重分配靠的是用户的唯一标识(比如用户ID)来关联,登录就是为了拿到这个标识;而Express Session的secret密钥是用来签名会话ID防篡改的,重分配本身不需要额外密钥,只要能合法操作会话存储就行。
具体实现流程
会话重分配说白了就是手动改请求的会话ID,重新加载旧会话数据,核心步骤:
- 用户登录验证通过后,从你自己维护的关联表(存用户ID和对应有效会话ID的表)里查这个用户的旧会话ID
- 销毁当前新会话:可以用Promise封装回调,比如
await new Promise(resolve => req.session.destroy(resolve)) - 把当前请求的会话ID换成旧的:
req.sessionID = 原有会话ID - 重新加载旧会话的数据:
await new Promise((resolve, reject) => req.session.reload(err => err ? reject(err) : resolve())) - 可选:更新关联表,让用户只绑定当前活跃的会话ID,避免一个用户绑多个会话
要注意的点:
- 操作会话的时候要处理异步回调,用Promise封装能避免回调地狱
- 会话存储(比如Redis、MongoDB)要支持快速查询和删除会话的操作
- 重分配后要确保响应头的
Set-Cookie更新成旧会话ID,让客户端之后的请求都用这个旧会话
内容的提问来源于stack exchange,提问作者GreenSaiko
相关产品推荐
相关产品推荐

