发请求时的 Promise 在什么情况下会进入 catch?

44 阅读2分钟

发请求时(fetch/axios/XMLHttpRequest),一个Promise什么时候会进入catch?

我曾经以为后端返回错误(400/500)就会进入catch,这其实是不对的。真正触发catch的条件是具体且有限的。

先说结论

Promise的catch的触发时机 = 请求本身失败,而不是业务失败 也就是说

  • 网络层失败
  • JS层抛异常
  • 框架内部认为请求是failure(此处的框架指的是发请求的工具,如fetch、axios、umi-request等,换句话说这里是否进入catch,不是由浏览器决定,而是由用的请求工具本身决定的)

才会进入catch。

业务层面的错误,例如接口返回的400、500、403、404、业务 code ≠ 0/200,不一定会触发错误。

下面我们逐个分析

fetch什么时候进入catch

fetch有个特性

fetch对http状态码不敏感,只要服务器有响应,就算是400/500,也会认为是成功的,会进入then

fetch的catch只会在真正的网络错误的时候触发

fetch触发catch的情况:

  1. DNS解析失败
  2. 请求超时
  3. 网络断开
  4. 无法连接服务器(服务器挂了或者拒绝连接)
  5. 被浏览器拦截(跨域CORS失败)
  6. fetch使用时js抛异常
fetch('/api/user')
  .then(res => {
    if (!res.ok) throw new Error('HTTP错误');
    return res.json();
  })
  .catch(err => {
    console.error('真正的失败:', err);
  });

axios什么时候进入catch

axios和fetch不同

axios会把HTTP状态码 >= 400的判定为失败,自动进入catch

axios触发catch的情况

  1. HTTP状态码4xx、5xx
    • 400 Bad Request
    • 401 Unauthorized
    • 403 Forbidden
    • 404 Not Found
    • 500 Server Error
  2. 网络错误
  3. cors跨域错误
  4. 请求超时
  5. 请求被取消
  6. JS异常
 axios.get('/api/user')
  .catch(err => {
    console.log(err); // 包含 response、request、message 等
  });

XMLHttpRequest 什么时候进入 catch?

XHR不返回Promise,但如果用Promise包了一层:

  • onerror -> 触发catch
  • onabort -> 触发catch
  • ontimeout -> 触发catch

http 4xx、5xx不会触发catch,会进入onload需要手动判断status。

统一总结

情况fetchaxios
网络断开catchcatch
服务器无法连接catchcatch
DNS错误catchcatch
CORS跨域catchcatch
请求超时catchcatch
请求被取消catchcatch
JS代码抛出异常catchcatch
HTTP 4xx、5xxthencatch
后端返回业务code != 0/200thenthen

核心区别

fetch:只要服务器有回应就不会进入catch

axios:服务器返回4xx、5xx就会进入进入catch