如何中断前端网络请求?🚀
1. 应用场景 💡
重复请求处理 🔄
- 场景:多个组件同时调用相同接口
- 解决:首次请求返回后取消其他请求
竞态问题处理 ⚡
- 场景:定时轮询时,前一个请求响应慢于后一个请求
- 解决:取消旧的未完成请求,只保留最新请求
路由切换请求处理 🔀
- 场景:SPA应用中组件卸载但请求仍在进行
- 解决:组件卸载时取消未完成的请求
文件上传控制 📤
- 场景:大文件上传时需要暂停/恢复功能
- 解决:通过请求取消实现上传控制
2. 实现方案 🛠️
2.1 Axios 取消请求
方案一:使用 CancelToken.source()
javascript
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
// 发起请求
axios.get('/api/data', {
cancelToken: source.token
}).catch(err => {
if (axios.isCancel(err)) {
console.log('请求已取消:', err.message);
}
});
// 取消请求
source.cancel('用户取消了请求');方案二:使用 CancelToken constructor
javascript
const CancelToken = axios.CancelToken;
let cancel;
axios.get('/api/data', {
cancelToken: new CancelToken(function(c) {
cancel = c;
})
});
// 取消请求
cancel('用户取消了请求');2.2 Fetch 取消请求
javascript
const controller = new AbortController();
const signal = controller.signal;
fetch('/api/data', { signal })
.then(response => response.json())
.catch(err => {
if (err.name === 'AbortError') {
console.log('请求已取消');
}
});
// 取消请求
controller.abort();3. 最佳实践 ⭐
3.1 React 组件中的使用示例
javascript
function DataComponent() {
const abortController = useRef(null);
useEffect(() => {
abortController.current = new AbortController();
fetchData(abortController.current.signal);
return () => {
// 组件卸载时取消请求
abortController.current?.abort();
};
}, []);
}3.2 防止竞态的请求封装
javascript
function createCancelableRequest() {
let currentRequest = null;
return async function request(url) {
// 取消之前的请求
if (currentRequest) {
currentRequest.abort();
}
const controller = new AbortController();
currentRequest = controller;
try {
const response = await fetch(url, { signal: controller.signal });
return await response.json();
} catch (error) {
if (error.name === 'AbortError') {
// 处理取消请求的情况
return null;
}
throw error;
}
};
}4. 注意事项 ⚠️
- Axios 取消请求后,请求的 Promise 会被 reject,需要正确处理错误
- 在组件卸载时要确保取消所有未完成的请求,避免内存泄漏
- AbortController 在低版本浏览器可能不支持,需要考虑兼容性
- 取消请求不会中断已经发送到服务器的请求,只是取消了对响应的处理
5. 浏览器兼容性 🌐
Fetch + AbortController:
- Chrome 66+
- Firefox 57+
- Safari 12.1+
- Edge 16+
XMLHttpRequest abort():
- 所有现代浏览器都支持