Skip to content

如何中断前端网络请求?🚀 ​

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. 注意事项 ⚠️ ​

  1. Axios 取消请求后,请求的 Promise 会被 reject,需要正确处理错误
  2. 在组件卸载时要确保取消所有未完成的请求,避免内存泄漏
  3. AbortController 在低版本浏览器可能不支持,需要考虑兼容性
  4. 取消请求不会中断已经发送到服务器的请求,只是取消了对响应的处理

5. 浏览器兼容性 🌐 ​

  • Fetch + AbortController:

    • Chrome 66+
    • Firefox 57+
    • Safari 12.1+
    • Edge 16+
  • XMLHttpRequest abort():

    • 所有现代浏览器都支持

6. 参考资料 📚 ​