执行登录路由时出现未处理的 Promise Rejection 警告错误

Posted

技术标签:

【中文标题】执行登录路由时出现未处理的 Promise Rejection 警告错误【英文标题】:Unhandled Promise Rejection Warning Error while executing login route 【发布时间】:2020-07-27 15:12:49 【问题描述】:

谁能解释我的错误并给我解决方案?

代码是

router.post("/login", (req, res, next) => 
  if(!req.body.email || !req.body.password)
    return res.status(401).json( success:false, message:'Email or Password Missing' );
  

  let fetchedUser;

  const isEmailValid = emailPatternMatch(req.body.email);
  if(!isEmailValid)
    return res.status(401).json( success:false, message:'Email not valid' );
  

  User.findOne(email: req.body.email)
    .then(user => 
      if (!user)
        return res.status(401).json( success: false, message:'Email Address is not Registered' );
      

      fetchedUser = user;
      return bcrypt.compare(req.body.password, user.password);
    )
    .then(result=> 
      if(!result)
        return res.status(401).json( success: false, message:'Incorrect Password' );
      
      const token = jwt.sign( email: fetchedUser.email, userId: fetchedUser._id , scretKey,  expiresIn: "1h"  );
      return res.status(200).json( success: true, token: token, userId: fetchedUser._id, expiresIn: 3600 );
    )
    .catch(err => 
      console.log(err);
      return res.status(401).json( success:false, message: 'Authentication Failed' );
    );
);

错误是

(节点:4084)UnhandledPromiseRejectionWarning:错误 [ERR_HTTP_HEADERS_SENT]:无法设置标头后发送到 客户 在 ServerResponse.setHeader (_http_outgoing.js:526:11) 在 ServerResponse.header (C:\Users\umesh\Desktop\Locationist\node_modules\express\lib\response.js:771:10) 在 ServerResponse.send (C:\Users\umesh\Desktop\Locationist\node_modules\express\lib\response.js:170:12) 在 ServerResponse.json (C:\Users\umesh\Desktop\Locationist\node_modules\express\lib\response.js:267:15) 在 C:\Users\umesh\Desktop\Locationist\backend\routes\user.js:82:30 在 processTicksAndRejections (internal/process/task_queues.js:97:5) (node:4084) UnhandledPromiseRejectionWarning:未处理的承诺拒绝。这 错误源于在异步函数内部抛出 没有 catch 块,或者拒绝一个没有 用 .catch() 处理。终止未处理的节点进程 承诺拒绝,使用 CLI 标志 --unhandled-rejections=strict (见https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode)。 (拒绝 ID:1)(节点:4084)[DEP0018] DeprecationWarning:未处理 不推荐使用承诺拒绝。在未来,承诺拒绝 未处理的将终止 Node.js 进程 非零退出代码。

【问题讨论】:

这种情况是否发生在任何特定情况下?例如。只有当您输入错误的密码或正确的密码或数据库中不存在电子邮件时? 您的代码以某种方式多次调用res.status().json(),这会引发错误,因为服务器无法多次响应单个浏览器请求。使用console.log(1), 2, 3, 4,看看它有多远以及什么时候变坏。如果您真的不关心,您可以使用 trycatch 将所有内容包装在您的路由中,或者您可以重构您的函数以使用 async/await,这将使您受益,因为您将能够以可预测的方式返回单个回应。 【参考方案1】:

我注意到在您的第一个 then 中,如果找不到用户,您正在调用 res.status。在您的下一个then 中,您可能会再次调用res.status,这将导致promise 被拒绝,因为它已经被调用了。在您的 catch 中,您再次调用 res.status,从而拒绝了没有任何问题的承诺,导致未处理的承诺。

要解决此问题,您需要避免多次调用res.status。你可以例如在你的then 中抛出一个异常并让你的catch 处理它:

...
User.findOne(email: req.body.email)
    .then(user => 
      if (!user)
        throw  success: false, message:'Email Address is not Registered' ;
      

      fetchedUser = user;
      return bcrypt.compare(req.body.password, user.password);
    )
    .then(result=> 
      if(!result)
        throw  success: false, message:'Incorrect Password' ;
      
      const token = jwt.sign( email: fetchedUser.email, userId: fetchedUser._id , scretKey,  expiresIn: "1h"  );
      return res.status(200).json( success: true, token: token, userId: fetchedUser._id, expiresIn: 3600 );
    )
    .catch(err => 
      console.log(err);
      return res.status(401).json(err);
    );

【讨论】:

当我从第一个 then 块返回一些东西时,它还会转到下一个 then 块吗? 是的。您(在预期的路径中)返回bcrypt.compare 并期待下一个then 的结果。如果在then 中返回一个promise(如bcrypt.compare),则该promise 的结果将传递给下一个then。如果在 then 中返回非承诺(或根本没有返回),则返回的值(或未定义)将传递给下一个 then

以上是关于执行登录路由时出现未处理的 Promise Rejection 警告错误的主要内容,如果未能解决你的问题,请参考以下文章

遵循 Shopify 的 React 和 Node 教程时出现未处理的运行时错误

Java - 在 for 循环中使用“继续”时出现未处理的异常错误?

从 Qt5Widgets 调用 setFixedSize() 时出现未处理的异常

ES6基础入门教程(十六)promise异步队列

promise 及 setTimeout 执行顺序

创建 MultiUserChat 房间时出现未授权错误