Axios 处理错误

Posted

技术标签:

【中文标题】Axios 处理错误【英文标题】:Axios handling errors 【发布时间】:2018-10-02 17:08:01 【问题描述】:

我正在尝试使用 Axios 更好地理解 javascript 承诺。我假装是处理 Request.js 中的所有错误,只从任何地方调用请求函数,而不必使用catch()

在此示例中,对请求的响应将为 400,并带有 JSON 格式的错误消息。

这是我得到的错误:

Uncaught (in promise) Error: Request failed with status code 400

我找到的唯一解决方案是在 Somewhere.js 中添加.catch(() => ),但我试图避免这样做。有可能吗?

代码如下:

请求.js

export function request(method, uri, body, headers) 
  let config = 
    method: method.toLowerCase(),
    url: uri,
    baseURL: API_URL,
    headers:  'Authorization': 'Bearer ' + getToken() ,
    validateStatus: function (status) 
      return status >= 200 && status < 400
    
  

  ...

  return axios(config).then(
    function (response) 
      return response.data
    
  ).catch(
    function (error) 
      console.log('Show error notification!')
      return Promise.reject(error)
    
  )

Somewhere.js

export default class Somewhere extends React.Component 

  ...

  callSomeRequest() 
    request('DELETE', '/some/request').then(
      () => 
        console.log('Request successful!')
      
    )
  

  ...


【问题讨论】:

你想打破承诺链吗? 不确定。这是否会阻止我在调用请求函数时不必使用 catch? 不成功的状态码在逻辑上是您应用程序中的异常状态吗?您希望调用代码对其做出什么反应? 如果您将错误发送到成功路径,您很可能需要测试它们以便在更高级别分支。我想说让成功成为成功,让错误成为错误,并相应地 .catch()。 【参考方案1】:

实际上,到目前为止,axios 是不可能的。只有2xx范围内的状态码才能被.then()捕获。

传统的方法是在catch() 块中捕获错误,如下所示:

axios.get('/api/xyz/abcd')
  .catch(function (error) 
    if (error.response) 
      // Request made and server responded
      console.log(error.response.data);
      console.log(error.response.status);
      console.log(error.response.headers);
     else if (error.request) 
      // The request was made but no response was received
      console.log(error.request);
     else 
      // Something happened in setting up the request that triggered an Error
      console.log('Error', error.message);
    

  );

另一种方法是在请求或响应被 then 或 catch 处理之前拦截它们。

axios.interceptors.request.use(function (config) 
    // Do something before request is sent
    return config;
  , function (error) 
    // Do something with request error
    return Promise.reject(error);
  );

// Add a response interceptor
axios.interceptors.response.use(function (response) 
    // Do something with response data
    return response;
  , function (error) 
    // Do something with response error
    return Promise.reject(error);
  );

【讨论】:

为什么你只在你的then 部分和Promise.reject 在你的catch 部分中使用简单的回报?对我来说似乎不太一致。 我使用了来自github官方axios文档的sn-p。 github.com/axios/axios#interceptors 无论如何,我认为您指的是interceptor 部分,但那里没有then。请求或响应在被处理之前被拦截,因此,我们还不想@​​987654333@。但是,如果遇到错误,如果我们愿意,我们可以Promise.reject()。或者,我们可以返回一些东西,然后在处理请求或响应时,我们可以使用Promise.reject()。同样的事情。 啊,是的,这很有道理!因此,在我们已经知道的错误情况下,不需要进一步处理请求,因此可以拒绝承诺。 谢谢,伙计!我不知道错误键也有error.request【参考方案2】:

如果你想访问整个错误正文,如下所示:

 async function login(reqBody) 
  try 
    let res = await Axios(
      method: 'post',
      url: 'https://myApi.com/path/to/endpoint',
      data: reqBody
    );

    let data = res.data;
    return data;
   catch (error) 
    console.log(error.response); // this is the main part. Use the response property from the error object

    return error.response;
  


【讨论】:

这真的解决了我的问题,谢谢elonaire【参考方案3】:

你可以这样: error.response.data 就我而言,我从后端获得了 error 属性。所以,我使用了 error.response.data.error

我的代码:

axios
  .get(`$API_BASE_URL/students`)
  .then(response => 
     return response.data
  )
  .then(data => 
     console.log(data)
  )
  .catch(error => 
     console.log(error.response.data.error)
  )

【讨论】:

【参考方案4】:

如果你想使用异步等待尝试

export const post = async ( link,data ) => 
const option = 
    method: 'post',
    url: `$URL$link`,
    validateStatus: function (status) 
        return status >= 200 && status < 300; // default
      ,
    data
;

try 
    const response = await axios(option);
 catch (error) 
    const  response  = error;
    const  request, ...errorObject  = response; // take everything but 'request'
    console.log(errorObject);

【讨论】:

我已经看到 error.response 未定义,然后它将在解构中失败【参考方案5】:

我尝试使用trycatch 方法,但它对我不起作用。但是,当我切换到使用.then(...).catch(...) 时,AxiosError 被正确捕获,我可以使用它。当我在设置断点时尝试前者时,它不允许我看到 AxiosError 而是告诉我捕获的错误是未定义的,这也是最终在 UI 中显示的内容。

不知道为什么会发生这种情况,我觉得这很简单。无论哪种方式,我都建议使用上面提到的常规.then(...).catch(...) 方法以避免向用户抛出未定义的错误。

【讨论】:

今天我也遇到了同样的情况:/ try..catch 仅适用于 async/await。您可以使用.catch()(捕获被拒绝的承诺)或try await axios... catch (err) ...(捕获被拒绝的承诺导致的异常)来处理它【参考方案6】:

如果我理解正确,您希望仅在请求成功时才调用请求函数的then,并且您希望忽略错误。为此,您可以创建一个新的 Promise 在 axios 请求成功时解决它,并且在失败的情况下永远不要拒绝它。

更新后的代码如下所示:

export function request(method, uri, body, headers) 
  let config = 
    method: method.toLowerCase(),
    url: uri,
    baseURL: API_URL,
    headers:  'Authorization': 'Bearer ' + getToken() ,
    validateStatus: function (status) 
      return status >= 200 && status < 400
    
  


  return new Promise(function(resolve, reject) 
    axios(config).then(
      function (response) 
        resolve(response.data)
      
    ).catch(
      function (error) 
        console.log('Show error notification!')
      
    )
  );


【讨论】:

不会造成内存泄漏吗?用户体验也将是“奇怪的”。无尽的微调器,而不是在页面上的正确位置清除错误消息。猜猜这不是让用户高兴的原因。我投票赞成在您提出请求的每个地方添加诚实的错误处理程序!)【参考方案7】:

从任何地方调用请求函数,而无需使用 catch()。

首先,虽然在一个地方处理大多数错误是一个好主意,但请求并不那么容易。应该传递一些错误(例如 400 个验证错误,例如:“用户名被占用”或“无效电子邮件”)。

所以我们现在使用基于 Promise 的函数:

const baseRequest = async (method: string, url: string, data: ?) =>
  new Promise< data: any >((resolve, reject) => 
    const requestConfig: any = 
      method,
      data,
      timeout: 10000,
      url,
      headers: ,
    ;

    try 
      const response = await axios(requestConfig);
      // Request Succeeded!
      resolve(response);
     catch (error) 
      // Request Failed!

      if (error.response) 
        // Request made and server responded
        reject(response);
       else if (error.request) 
        // The request was made but no response was received
        reject(response);
       else 
        // Something happened in setting up the request that triggered an Error
        reject(response);
      
    
  ;

然后你可以像这样使用请求

try 
  response = await baseRequest('GET', 'https://myApi.com/path/to/endpoint')
 catch (error) 
  // either handle errors or don't

【讨论】:

抱歉吹毛求疵,但有两件事:如果你真的想使用 async 将它移到你的 promise resolve/reject 函数前面。或者理想情况下,甚至不用费心使用 Promise(因为您将 baseRequest 包装在异步装饰器中),只需继续您的 try/catch 和错误类型分支,只需使用 return 而不是 resolve。其次,我喜欢没有服务器响应的测试!但是当axios超时的时候,会不会抛出异常,被当作服务器没有返回响应?还是这些场景是一回事? 感谢airtonix的建议。这个功能已经很老了,我总是很乐意改进代码。此函数中 async/await 和 Promises 的混合并不理想。你能编辑我的评论以反映这些变化吗? RE 您的问题 AFAIK axios 在代码的catch 部分中处理这两个问题。我会手动将超时设置为非常低,以测试我对超时的错误处理。 “缺席服务器”是指 404 错误?还是没有网络错误?全部在 catch 块中处理,因此请尝试自己触发它们进行测试。【参考方案8】:

处理响应类型设置为流的 axios 错误的一种方法对我有用。

.....
.....
try
   .....
   .....
   // make request with responseType: 'stream'
   const url = "your url";
   const response = axios.get(url,  responseType: "stream" );
   // If everything OK, pipe to a file or whatever you intended to do
   // with the response stream
   .....
   .....
 catch(err)
  // Verify it's axios error
  if(axios.isAxios(err))
    let errorString = "";
    const streamError = await new Promise((resolve, reject) => 
      err.response.data
        .on("data", (chunk) => 
           errorString += chunk;
          
        .on("end", () => 
           resolve(errorString);
         
      );
    // your stream error is stored at variable streamError.
    // If your string is JSON string, then parse it like this
    const jsonStreamError = JSON.parse(streamError as string);
    console.log( jsonStreamError )
    // or do what you usually do with your error message
    .....
    .....
  
  .....
  .....

   
  

【讨论】:

【参考方案9】:

为了可重用性:

创建文件errorHandler.js:

export const errorHandler = (error) => 
  const  request, response  = error;
  if (response) 
    const  message  = response.data;
    const status = response.status;
    return 
      message,
      status,
    ;
   else if (request) 
    //request sent but no response received
    return 
      message: "server time out",
      status: 503,
    ;
   else 
    // Something happened in setting up the request that triggered an Error
    return  message: "opps! something went wrong while setting up request" ;
  
;

然后,每当你发现 axios 的错误时:

Just import error handler from errorHandler.js and use like this.
  try 
    //your API calls 
   catch (error) 
    const  message: errorMessage  = errorHandlerForAction(error);
     //grab message
  

【讨论】:

以上是关于Axios 处理错误的主要内容,如果未能解决你的问题,请参考以下文章

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

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

避免在每个请求中使用 Axios 在 Vue 中响应错误时进行处理

axios响应拦截器错误处理及思想

无法使用 try 和 catch 处理 axios 中的 404 错误

将 axios 响应错误存储在 axios store 中并在组件内处理它是一种好习惯吗?