UnhandledPromiseRejectionWarning:此错误源于在没有 catch 块的情况下抛出异步函数内部

Posted

技术标签:

【中文标题】UnhandledPromiseRejectionWarning:此错误源于在没有 catch 块的情况下抛出异步函数内部【英文标题】:UnhandledPromiseRejectionWarning: This error originated either by throwing inside of an async function without a catch block 【发布时间】:2019-05-25 04:30:27 【问题描述】:

我的 Node-Express 应用程序出现以下错误

UnhandledPromiseRejectionWarning:未处理的承诺拒绝。这 错误源于在异步函数内部抛出 没有 catch 块,或拒绝未处理的承诺 使用 .catch()。 (拒绝编号:4)

至少可以说,我创建了一个看起来像这样的辅助函数

const getEmails = (userID, targettedEndpoint, headerAccessToken) => 
    return axios.get(base_url + userID + targettedEndpoint,   headers: "Authorization" : `Bearer $headerAccessToken` )
    .catch(error =>  throw error)

然后我正在导入这个辅助函数

const gmaiLHelper = require("./../helper/gmail_helper")

并像这样在我的 api 路由中调用它

router.get("/emailfetch", authCheck, async (req, res) => 
  //listing messages in users mailbox 
  let emailFetch = await gmaiLHelper.getEmails(req.user._doc.profile_id , '/messages', req.user.accessToken)
  .catch(error =>  throw error)
  emailFetch = emailFetch.data
  res.send(emailFetch)
)

从我的角度来看,我认为我正在使用 catch 块来处理错误。

问题:谁能解释我为什么会收到错误以及如何解决它?

【问题讨论】:

尝试用console.log(error)替换throw error helper functionapi? .......两个 @ic3b3rg 这不是处理拒绝的正确方法。这将导致另一个拒绝,因为emailFetchundefined 【参考方案1】:

.catch(error => throw error) 是空操作。它会导致路由处理程序中未处理的拒绝。

正如this answer 中所述,Express 不支持承诺,所有拒绝都应手动处理:

router.get("/emailfetch", authCheck, async (req, res, next) => 
  try 
  //listing messages in users mailbox 
    let emailFetch = await gmaiLHelper.getEmails(req.user._doc.profile_id , '/messages', req.user.accessToken)
    emailFetch = emailFetch.data
    res.send(emailFetch)
   catch (err) 
    next(err);
  
)

【讨论】:

或者你可以用express-promise-router替换路由器,因为这个包为你完成了这项工作,不再需要将代码嵌入到try catch块中。 const router = require('express-promise-router')(); Estus,所以如果我们使用普通的 Promise,而不是使用 async 和 await。我们还能期待这个错误吗? (没有尝试捕获)还是我应该重新阅读您的答案? (这次可能更仔细) @VarunBindal 是的,您可能会遇到错误。 async/await 只是原始承诺的语法糖。任何async 函数都可以用普通的 ES6 重写。 @estus 为什么我们需要在上面使用next()?考虑到如果它在这里抛出错误没有任何其他路线。此外,删除 next 会得到 **UnhandledPromiseRejectionWarning: This error originated either by throwing inside of an async function without a catch block** (even when I am using try...catch` next(err) 存在是因为错误通常需要以某种方式处理。如果您仍然有 UnhandledPromiseRejectionWarning,那么您的代码与发布的代码不同。你可能会忘记链接一些承诺,否则。处理得当就不可能有未处理的promise。【参考方案2】:

我建议从 getMails 中删除以下代码

 .catch(error =>  throw error)

在你的 main 函数中,你应该将 await 和相关代码放在 Try 块中,并在你失败的代码处添加一个 catch 块。


你的函数 gmaiLHelper.getEmails 应该返回一个包含拒绝和解决的承诺。

现在在调用和使用 await 时,将其放入 try catch 块(删除 .catch),如下所示。

router.get("/emailfetch", authCheck, async (req, res) => 
  //listing messages in users mailbox 
try
  let emailFetch = await gmaiLHelper.getEmails(req.user._doc.profile_id , '/messages', req.user.accessToken)

catch (error)  
 // your catch block code goes here
)

【讨论】:

谢谢 Sumer,您能否通过更改我的代码来添加您的意思并将其包含在示例中 添加了详细信息。【参考方案3】:

您正在捕获错误,但随后又将其抛出。您应该尝试更优雅地处理它,否则您的用户将看到 500,内部服务器,错误。

您可能想要发回一个响应,告诉用户出了什么问题,并在您的服务器上记录错误。

我不确定请求可能返回的确切错误,您可能希望返回类似的内容。

router.get("/emailfetch", authCheck, async (req, res) => 
  try 
    let emailFetch = await gmaiLHelper.getEmails(req.user._doc.profile_id , '/messages', req.user.accessToken)
      emailFetch = emailFetch.data
      res.send(emailFetch)
    catch(error) 
      res.status(error.response.status)
      return res.send(error.message);
    )

)

需要修改此代码以匹配您从 axios 调用中获得的错误。

我也将代码转换为使用 try 和 catch 语法,因为您已经在使用 async。

【讨论】:

感谢 tmcinol,您能否通过更改我的代码来添加您的意思,并将其包含在示例中【参考方案4】:

在您的应用上使用 express-async-errors

喜欢这个

app.ts

import 'express-async-errors'

稍后,配置您的应用程序以读取错误实例。

类自定义错误

class Error
  
  public readonly message: string;
  public readonly statusCode: number;
  public readonly data?: any

  constructor(message: string, statusCode = 400, data?: any)
    this.message = message;
    this.statusCode = statusCode;
    this.data = data;
  


export default Error

在您的应用上使用的中间件 -> app.use(youMiddleware())

import  Request, Response, NextFunction  from 'express'
import AppError from '../errors/AppError'

function globalErrors(err: Error, request: Request, response: Response, next: NextFunction) 

  if (err instanceof AppError) 
    response.status(err.statusCode).json(
      status: 'error',
      message: err.message,
      data: err?.data
    );
  

  console.error(err);

  return response.status(500).json(
    status: 'error',
    message: 'Internal server error'
  );



export  globalErrors ;

【讨论】:

【参考方案5】:

我解决了这个问题。这很简单。如果你检查关心问题可能是因为辅助变量有空格。为什么 ?我不知道,但是你必须使用 trim() 方法并且会解决问题

【讨论】:

请解释auxiliar variable 的含义。不清楚。 不清楚这是什么意思,但认为他提出的解决方案不再使此错误发生哈哈

以上是关于UnhandledPromiseRejectionWarning:此错误源于在没有 catch 块的情况下抛出异步函数内部的主要内容,如果未能解决你的问题,请参考以下文章

[Unhandled promise rejection: TypeError: null is not an object (evaluating '_reactNativeImageCropPic

等待 - 捕获错误 - UnhandledPromiseRejectionWarning

批量删除如何工作?

7月工作知识总计:

未处理的承诺拒绝 |重启命令

未处理的承诺拒绝警告(Cordova Angular)