发请求时(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的情况:
- DNS解析失败
- 请求超时
- 网络断开
- 无法连接服务器(服务器挂了或者拒绝连接)
- 被浏览器拦截(跨域CORS失败)
- 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的情况
- HTTP状态码4xx、5xx
- 400 Bad Request
- 401 Unauthorized
- 403 Forbidden
- 404 Not Found
- 500 Server Error
- 网络错误
- cors跨域错误
- 请求超时
- 请求被取消
- 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。
统一总结
| 情况 | fetch | axios |
|---|---|---|
| 网络断开 | catch | catch |
| 服务器无法连接 | catch | catch |
| DNS错误 | catch | catch |
| CORS跨域 | catch | catch |
| 请求超时 | catch | catch |
| 请求被取消 | catch | catch |
| JS代码抛出异常 | catch | catch |
| HTTP 4xx、5xx | then | catch |
| 后端返回业务code != 0/200 | then | then |
核心区别
fetch:只要服务器有回应就不会进入catch
axios:服务器返回4xx、5xx就会进入进入catch