如何在Express服务中使用Passport.js实现注册时自动保存用户会话数据
你遇到的ERR_HTTP_HEADERS_SENT报错根源是执行顺序错误:你之前的代码在调用res.send(data)把响应返回给客户端后,才执行req.login操作,而req.login会修改会话对应的Set-Cookie响应头,此时响应已经发送完毕,自然会抛出无法修改已发送响应头的错误。
解决方案
不需要额外自定义Passport策略,也不需要复用现有LocalStrategy,只需要调整注册接口的执行顺序,用户数据写入数据库成功后,先调用req.login完成会话写入,再返回响应即可。req.login是Passport官方暴露的原生方法,和passport.authenticate内部调用的是同一套逻辑,会自动触发你已经配置好的用户序列化流程,将用户信息写入服务端会话。
修改后的注册接口代码如下:
router.post('/signup', (req, res) => { const user = { first_name: req.body.first_name, last_name: req.body.last_name, email: req.body.email, password: req.body.password, }; User.findOrCreate({where: {email: user.email}, defaults: user}) .then(([dbUser, created]) => { // 邮箱已存在的情况处理 if (!created) { return res.status(400).send({message: "该邮箱已被注册"}); } // 手动调用login写入会话,完成后再返回响应 req.login(dbUser, (err) => { if (err) { return res.status(500).send({message: "会话创建失败"}); } res.json(dbUser); }); }) .catch(err => { res.status(500).send({ message: err.message || "创建用户时发生错误" }); }); });
如果偏好async/await写法,可以用以下更简洁的实现:
router.post('/signup', async (req, res) => { try { const user = { first_name: req.body.first_name, last_name: req.body.last_name, email: req.body.email, password: req.body.password, }; const [dbUser, created] = await User.findOrCreate({ where: {email: user.email}, defaults: user }); if (!created) { return res.status(400).send({message: "该邮箱已被注册"}); } // 封装req.login为Promise形式适配async/await await new Promise((resolve, reject) => { req.login(dbUser, (err) => err ? reject(err) : resolve()); }); res.json(dbUser); } catch (err) { res.status(500).send({ message: err.message || "创建用户时发生错误" }); } });
内容的提问来源于stack exchange,提问作者gnp210
相关产品推荐
相关产品推荐

