Axios处理错误

328

我正在尝试使用Axios更好地理解JavaScript Promise。我的目标是在Request.js中处理所有错误,并且只需从任何地方调用请求函数而无需使用catch()

在这个例子中,请求的响应将是400,JSON中包含错误消息。

这是我遇到的错误:

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

我唯一找到的解决方法是在Somewhere.js中添加.catch(() => {}),但我正在努力避免这样做。这可能吗?

以下是代码:

Request.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)
    }
  )
}

某个地方.js

export default class Somewhere extends React.Component {

  ...

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

  ...

}

你想要打破承诺链吗? - Niyoko
我不确定。这是否意味着我在调用请求函数时不必使用catch? - mignz
在您的应用程序中,一个不成功的状态代码是否在逻辑上是一个异常状态?您希望调用代码如何对此做出反应? - Benjamin Gruenbaum
1
如果您将错误沿着成功的路径发送,很有可能需要在某个更高的级别上测试它们以进行分支。我会说让成功成为成功,让错误成为错误,并相应地.catch()。 - Roamer-1888
15个回答

442
如果你想处理请求模块中的所有基本错误,而不需要在每个调用上使用catch,那么Axios的方法是在响应上使用一个拦截器
axios.interceptors.response.use(function (response) {
    // Optional: Do something with response data
    return response;
  }, function (error) {
    // Do whatever you want with the response error here:

    // But, be SURE to return the rejected promise, so the caller still has 
    // the option of additional specialized handling at the call-site:
    return Promise.reject(error);
  });

如果你从axios拦截器中返回错误,那么你仍然可以使用传统的方法,通过catch()块来处理,如下所示:
axios.get('/api/xyz/abcd')
  .catch(function (error) {
    if (error.response) {
      // The request was made and the server responded with a status code
      // that falls out of the range of 2xx
      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
      // `error.request` is an instance of XMLHttpRequest in the browser 
      // and an instance of http.ClientRequest in node.js
      console.log(error.request);
    } else {
      // Something happened in setting up the request that triggered an Error
      console.log('Error', error.message);
    }
   
  });

1
为什么你在 then 部分只使用简单的返回语句,在 catch 部分却使用 Promise.reject?这对我来说似乎不太一致。 - winklerrr
1
我使用了来自axios官方github文档的代码片段。https://github.com/axios/axios#interceptors - Plabon Dutta
4
无论如何,我认为你指的是“拦截器”部分,但那里没有“then”。请求或响应在处理之前被拦截,因此我们不想立即使用Promise.resolve()。但是,如果遇到错误,我们可以选择使用Promise.reject()。或者,我们可以返回一些东西,稍后当请求或响应被处理时,我们可以使用Promise.reject()。同样的事情。 - Plabon Dutta
1
尝试使用 error.response。希望大家都在寻找这个。它将提供服务器返回的正确的错误详细信息。 - Anuj Raghuvanshi
1
catch(error) { ... } 而不是 catch(function(error) { ... } ),你从哪里得来的? - Normal
显示剩余3条评论

134

如果您想要访问整个错误体,请按照下面所示操作:

 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;
  }

}

如果错误没有被捕获或者程序挂起,就在错误块下面再加一个 try-catch。 - Durian Jaykin
1
你说的“获得完整错误信息体”是什么意思?上面/之前由@plabondutta提供的答案可以获得完整的错误信息体... - XML

100

您可以这样操作: 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)
  })

36

如果您想使用异步等待,请尝试

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);
}

8
我曾看到"error.response"未定义,然后在解构过程中会出错。 - SijuMathew

7

我尝试使用 try{}catch{} 方法,但它对我没有起作用。然而,当我转而使用 .then(...).catch(...) 时,可以正确地捕获 AxiosError,以便我可以进行调试。在我尝试前者并设置断点时,它不允许我查看 AxiosError,并且告诉我捕获的错误是未定义的,这也最终显示在 UI 中。

我不确定为什么会发生这种情况,但我认为这很琐碎。总之,由于这个原因,我建议使用上述传统的 .then(...).catch(...) 方法,以避免向用户抛出未定义的错误。


7
try..catch 只能用于 async/await。您可以使用 .catch() 处理拒绝的 Promise,或者使用 try { await axios... } catch (err) {...} 来处理由拒绝的 Promise 引起的异常。 - BankBuilder

6
为了实现代码的可重用性: 创建一个 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
  }

4
axios
  .get(`${API_BASE_URL}/students`)
  .then(res => {
     return res.data
  })
  .then((data)=> {
     console.log(data)
  })
  .catch(error => {
     console.log(error)
  })

尝试这种方式,它可以正常工作


4
如果我理解正确,您希望仅在请求成功时调用then函数,并忽略错误。为了实现这一点,您可以创建一个新的promise,在axios请求成功时resolve它,并在失败情况下不reject它。
更新后的代码将如下所示:
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!')
      }
    )
  });

}

会不会导致内存泄漏?用户体验也会变得“奇怪”。页面上应该清晰地显示错误信息,而不是无尽的旋转图标。我猜这并不能让用户感到满意。我的建议是在每个请求的位置都添加一个诚实的错误处理程序! - 12kb

3

https://stackabuse.com/handling-errors-with-axios/

    let res = await axios.get('/my-api-route');

    // Work with the response...
} catch (err) {
    if (err.response) {
        // The client was given an error response (5xx, 4xx)
    } else if (err.request) {
        // The client never received a response, and the request was never left
    } else {
        // Anything else
    }
}

try {
    let res = await axios.get('/my-api-route');

    // Work with the response...
} catch (err) {
    if (err.response) {
        // The client was given an error response (5xx, 4xx)
    } else if (err.request) {
        // The client never received a response, and the request was never left
        console.log(err.request);
    } else {
        // Anything else
    }
}

2

以下是我用于处理响应类型设置为流时的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
    .....
    .....
  }
  .....
  .....
}
   
  

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接