express-session跨函数获取req.session.id值不一致如何排查
问题根因与解决步骤
1 核心错误:占用了express-session的内置属性req.session.id
req.session.id是express-session框架内置的会话唯一标识,由框架自动生成、维护,禁止开发者手动覆盖这个属性,你强行赋值会导致框架无法正确匹配会话,后续请求拿到的都是新生成的会话,所以两次打印的id不一样。
你需要把自定义的用户数据库id存在其他字段上,比如req.session.userId。
2 第二个错误:数据库查询结果取值错误
mysql的query回调返回的row是匹配结果的数组,哪怕只有一条匹配数据,也需要取row[0]才能拿到用户对象,你直接写row.id取到的是undefined,之前打印出来的是框架自带的session id,根本不是你要的用户id。
3 跨域配置缺失导致会话不共享
你开启了CORS跨域,但默认配置下跨域请求不会携带cookie,每次请求都会生成新的会话,也是session id不一致的常见原因,需要前后端同时配置:
后端配置修改
- 修改cors配置,指定允许的前端域名,开启凭证支持:
// 替换成你的前端实际访问地址,不能用* app.use(cors({ origin: 'http://localhost:3000', credentials: true }))
- 修改session配置,添加cookie相关参数:
app.use( session({ secret: "Shh, its a secret!", resave: false, saveUninitialized: false, // 未登录的空会话不要保存,减少无效会话 cookie: { httpOnly: true, secure: false, // 开发环境用http的话设为false,生产https环境设为true sameSite: 'lax', maxAge: 24 * 60 * 60 * 1000 // 会话有效期1天,按需调整 } }) );
前端配置修改
发请求时开启携带凭证的配置:
- 用axios的话:
axios.defaults.withCredentials = true - 用fetch的话:请求参数加
credentials: 'include'
4 代码修改示例
登录接口修改
if (row.length > 0) { // 不要用id作为key,换用userId存用户的数据库id req.session.userId = row[0].id; console.log("🚀 ~ 登录成功,用户id", req.session.userId) req.session.isLoggedIn = true; req.session.username = row[0].username; }
报表查询接口修改
exports.findByWorkerId = function (req, res) { // 从userId字段取值 const id = req.session.userId; console.log("🚀 ~ 报表查询拿到的用户id", id) if (!id || !req.session.isLoggedIn) { return res.status(401).send("请先登录"); } // 后续查询逻辑不变 Report.findByWorkerId(id, function (err, report) { if (err) return res .status(500) .send("Error occured during fetching report for id " + id); console.log("report: ", report); return res.send(report); }); };
排查验证步骤
- 在两个接口都打印完整的
req.session对象,查看登录时设置的test2、isLoggedIn字段是否在报表接口中存在,如果不存在就是跨域配置问题导致会话不共享 - 如果字段存在但
userId不对,检查数据库查询时的取值是否正确
内容的提问来源于stack exchange,提问作者Engin Karataş
相关产品推荐
相关产品推荐

