使用 axios 处理来自异步等待语法的错误

Posted

技术标签:

【中文标题】使用 axios 处理来自异步等待语法的错误【英文标题】:Handling error from async await syntax with axios 【发布时间】:2019-03-01 21:32:19 【问题描述】:

这是我的代码块:

  const getToken = async () => 
    try 
      const token = await axios.post(keys.sessionURL, 
        email: keys.verificationEmail,
        password: keys.verificationPassword,
      );
     catch (err) 
      throw new Error('Unable to establish a login session.'); // here I'd like to send the error to the user instead
    
  ;

如您所见,我正在连接到外部服务器以获取令牌。那行得通。现在,我想捕获一个错误,但这次不是“抛出新错误”,而是我想将它发送给用户,所以我想要这样的东西:

res.status(401).send('Unable to get a token');

但是因为我不在路由处理程序中,所以我不能使用“res”。那我怎样才能把它发送给用户呢?

谢谢!

【问题讨论】:

您可以在路由处理程序中等待 getToken 并在那里捕获异常。然后你就可以访问你的 res 对象了。如果您提供有关如何调用 getToken 的更多信息,我可以向您展示一个示例 【参考方案1】:

优雅且带有 TypeScript。

import axios,  AxiosResponse  from "axios";
...

const response: void | AxiosResponse<any, any> = await axios(
  headers: 
    Authorization: `Bearer $XYZ`,
    Accept: "application/json",
  ,
  method: "GET",
  params: 
    ...
  ,
  url: "https://api.abcd.com/...",
).catch((error: unknown) => 
  if (error instanceof Error) 
    console.error(
      "Error with fetching ..., details: ",
      error
    );
  
);

【讨论】:

【参考方案2】:

保持async / await的优雅:

const result = await axios.post('/url', params)
    .catch((err) => 
       // deal with err, such as toggle loading state, recover click and scroll.
       this.loading = false;
       // recover the reject state before.
       return Promise.reject(err);
    );

this.data = result; // not exec when reject

【讨论】:

【参考方案3】:

try/catch 不是一个好的解决方案。它的目的是捕获运行时错误,而不是来自 axios 的 HTTP 错误,如果错误由拦截器处理,然后通过 return Promise.reject(error); 传递回调用者@

这里是拦截器示例

axios.interceptors.response.use(
  response => 
    //maybe process here
    return response;
  ,
  error => 
    //do some global magic with error and pass back to caller
    return Promise.reject(error);
  
);

让我们从 try/catch 不起作用的示例开始

for(let i=0; i<5;i++) 

    try
       const result = async axios.get(`$/item/i`);
    
    catch(error) 
       //error undefined here, you would expect an error from pattern like axios.get(...).then(...).catch(real_http_error) 
    

我发现这种模式行得通。假设由于 JS 的异步特性,您想循环调用以避免多次 http 调用。

for(let i=0; i<5;i++) 

    const result = async axios.get(`$/item/i`).catch(error)   //chain catch despite async keyword
       //now you access http error and you can do something with it
       //but calling break; or return; won't break for loop because you are in a callback
    

    if(!result)  //due to http error
        continute; //keep looping for next call
        //or break; to stop processing after 1st error
    
    
    //process response here, result.data...

【讨论】:

很好的答案,因为在这种情况下,您不需要将每个 axios 函数都包装到 try / catch 中。使用它。【参考方案4】:

对于 axios 版本-0.19.0,经过数小时的异步等待后,代码工作正常。但不确定其他版本!

catch(error)
console.log(error.response.data.error)

希望有帮助!

【讨论】:

我觉得这是迄今为止这个问题的最佳答案。与其他人不同,它实际上使用触发错误提供的数据,并允许进一步处理。好一个,Akshay ? 答案应该被投票为正确答案。它允许前端检索来自后端的错误。这保存了我的项目 挣扎了一个小时,这救了我! 显示错误 TypeError: Cannot read properties of undefined (reading 'data')【参考方案5】:

在我的解决方案中我使用:

try
    let responseData = await axios.get(this.apiBookGetBookPages + bookId, headers);
    console.log(responseData);
catch(error)
    console.log(Object.keys(error), error.message);

如果某些事情失败了,我们会得到这样的错误:

[ 'config', 'request', 'response', 'isAxiosError', 'toJSON' ] 
'Request failed with status code 401'

我们也可以获取状态码:

...
catch(error)
    if(error.response && error.response.status == 401)
            console.log('Token not valid!');
    

【讨论】:

【参考方案6】:

你可以保持几乎相同的功能

const getToken = async () => 
  try 
    const token = await axios.post(keys.sessionURL, 
      email: keys.verificationEmail,
      password: keys.verificationPassword,
    )
   catch (err) 
    throw new Error('Unable to get a token.')
  

然后从您的路由处理程序中 catch 最终异常

app.get('/endpoint', async (req, res) => 
  try 
    const token = await getToken()

    // Do your stuff with the token
    // ...

   catch (err) 
     // Error handling here
     return res.status(401).send(err.message);
  
)

默认的js异常系统可以很好的通过调用栈传递错误数据。

【讨论】:

【参考方案7】:

您保留isAuthError 之类的标志,如果发生错误,则将其作为真发送,如果标志isAuthError 为真,则在主函数中抛出错误并在 catch 中处理,否则执行您的操作。我在下面添加了一个示例。希望对你有帮助

const getToken = async () => 
    try 
      const token = await axios.post(keys.sessionURL, 
        email: keys.verificationEmail,
        password: keys.verificationPassword,
      );
      return token, isAuthError: false;
     catch (err) 
      // throw new Error('Unable to establish a login session.'); // here I'd like to send the error to the user instead
      return err, isAuthError: true;
    
  ;

主函数

app.post('/login', async (req, res)=>
  try
    // some validations

    let data = await getToken();
    if( data.isAuthError)
      throw data.err;
    
    let token = data.token;
    //do further required operations
  catch(err)
     //handle your error here with whatever status you need
     return res.status(500).send(err);
  
)

【讨论】:

这听起来像是需要额外步骤的错误处理:)

以上是关于使用 axios 处理来自异步等待语法的错误的主要内容,如果未能解决你的问题,请参考以下文章

我的 Redux 处理来自 axios 的错误应该使用不同的操作还是使用附加数据的相同操作?

Vue + Axios 处理来自服务器的所有请求错误

处理 Mongoose 异步/等待调用中的错误

Discord bot异步/等待错误处理

AlamoFire downloadProgress 完成处理程序到异步/等待

如何在单元测试之前等待组件的挂载回调中的异步调用完成?