出现Error [ERR_HTTP_HEADERS_SENT]错误,求排查Passport登录逻辑问题
问题原因及修复方案
核心问题1:Passport验证回调中多次调用done()
你的Passport LocalStrategy验证回调存在逻辑漏洞:当用户存在且有密码时,调用异步的bcrypt.compare后,没有阻止后续代码执行。也就是说,bcrypt.compare还在异步处理时,代码已经走到了下方的return done(null, false, { message: "Please login with Google or Facebook" });,导致done()被调用两次——一次是bcrypt.compare回调内的调用,一次是后续return语句的调用。
Passport会在每次调用done()时尝试发送响应,两次调用直接触发「Cannot set headers after they are sent to the client」错误。
修复代码:
passport.use( new LocalStrategy( { usernameField: "signinEmail", passwordField: "signinPassword", }, async (email, password, done) => { const user = await userService.getByEmailOrPhone(email); if (user) { if (user.password) { // 添加return阻止后续代码执行 return bcrypt.compare(password, user.password, (err, res) => { if (!err) { if (res) { return done(null, user); } return done(null, false, { message: "Incorrect password" }); } console.log(err); // 错误时调用done传递错误,避免请求挂起 return done(err); }); } return done(null, false, { message: "Please login with Google or Facebook", }); } return done(null, false, { message: "Incorrect login" }); } ) );
核心问题2:中间件顺序错误+参数逻辑错误
你的路由中,passport.authenticate("local")在validationMiddleware之前执行,意味着Passport会先尝试认证,再做参数验证,逻辑完全颠倒。正确顺序应该是先验证参数合法性,再执行认证。同时原代码的asyncHandler参数、用户信息取值路径都存在错误:
修复代码:
router.post( "/login", // 先做参数验证 validationMiddleware({ signinEmail: ["required", "email"], signinPassword: ["required", "min:6"], }), // 再执行Passport认证 passport.authenticate("local"), // 修正asyncHandler的参数为标准(req, res, next) asyncHandler(async (req, res, next) => { // 修正用户信息取值路径为req.user const { accessToken, refreshToken } = await authService.authorizeById( req.user.user_id ); if (accessToken) { return res.send({ accessToken, refreshToken, success: true, }); } throw new UnauthorizedException(""); }) );
额外优化建议
把bcrypt.compare改成Promise风格调用,和整个回调的async/await风格统一,避免回调嵌套带来的逻辑混乱:
// 替换回调风格的bcrypt.compare const isMatch = await bcrypt.compare(password, user.password); if (isMatch) { return done(null, user); } return done(null, false, { message: "Incorrect password" });
内容的提问来源于stack exchange,提问作者Dmytro Hl
相关产品推荐
相关产品推荐

