IT评测·应用市场-qidao123.com

标题: Axios 请求取消:从原理到实践 [打印本页]

作者: 渣渣兔    时间: 2025-3-19 12:56
标题: Axios 请求取消:从原理到实践
Axios 请求取消:从原理到实践

在现代前端开辟中,网络请求是不可或缺的一部门。Axios 是一个基于 Promise 的 HTTP 客户端,广泛应用于浏览器和 Node.js 环境中。然而,在某些场景下,我们可能需要取消正在进行的请求,比方用户在请求完成前跳转到其他页面,大概重复触发雷同的请求时取消之前的请求。本文将深入探讨 Axios 请求取消的原理,并通过一个二次封装的例子来演示怎样实现请求取消。
1. 请求取消的原理

Axios 的请求取消功能依赖于 CancelToken。CancelToken 是一个用于取消请求的令牌,它可以通过 CancelToken.source() 方法创建。每个 CancelToken 实例都有一个 token 和一个 cancel 方法。当调用 cancel 方法时,与该 token 关联的请求将被取消。
1.1 CancelToken 的工作原理

1.2 取消请求的流程

2. 二次封装 Axios 实现请求取消

为了更好地管理请求取消逻辑,我们可以对 Axios 进行二次封装。以下是一个简单的封装示例,展示了怎样在封装中实现请求取消功能。

1. 代码结构分析

1.1 Axios 实例的创建

  1. const instance: AxiosInstance = axios.create({
  2.   baseURL: import.meta.env.VITE_API_BASE_URL,
  3.   timeout: 10000,
  4.   headers: {
  5.     'Content-Type': 'application/json',
  6.   },
  7. });
复制代码

通过 axios.create 创建了一个 Axios 实例 instance,后续的全部请求都将基于这个实例。

1.2 取消令牌的管理

  1. const cancelTokenMap = new Map<string, CancelTokenSource>();
复制代码


1.3 请求拦截器

  1. instance.interceptors.request.use(
  2.   (config) => {
  3.     // 添加 token 到请求头
  4.     const token = localStorage.getItem('token');
  5.     if (token) {
  6.       config.headers = config.headers || {};
  7.       config.headers.Authorization = `Bearer ${token}`;
  8.     }
  9.     return config;
  10.   },
  11.   (error) => {
  12.     return Promise.reject(error);
  13.   }
  14. );
复制代码


1.4 响应拦截器

  1. instance.interceptors.response.use(
  2.   (response: AxiosResponse) => {
  3.     // 清理已完成的请求记录
  4.     const url = response.config.url;
  5.     if (url && cancelTokenMap.has(url)) {
  6.       cancelTokenMap.delete(url);
  7.     }
  8.     // 处理全局响应逻辑
  9.     if (response.data.code !== 0) {
  10.       return Promise.reject(response.data);
  11.     }
  12.     return response.data;
  13.   },
  14.   (error) => {
  15.     // 清理失败的请求记录
  16.     const url = error.config?.url;
  17.     if (url && cancelTokenMap.has(url)) {
  18.       cancelTokenMap.delete(url);
  19.     }
  20.     // 处理全局错误
  21.     if (error.response?.status === 401) {
  22.       // 处理未授权
  23.       window.location.href = '/login';
  24.     }
  25.     return Promise.reject(error);
  26.   }
  27. );
复制代码


1.5 封装的请求方法

  1. const http = {
  2.   get: <T>(url: string, config?: AxiosRequestConfig): Promise<T> => {
  3.     const source = axios.CancelToken.source();
  4.     cancelTokenMap.set(url, source);
  5.     return instance.get(url, { ...config, cancelToken: source.token });
  6.   },
  7.   post: <T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> => {
  8.     const source = axios.CancelToken.source();
  9.     cancelTokenMap.set(url, source);
  10.     return instance.post(url, data, { ...config, cancelToken: source.token });
  11.   },
  12.   put: <T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> => {
  13.     const source = axios.CancelToken.source();
  14.     cancelTokenMap.set(url, source);
  15.     return instance.put(url, data, { ...config, cancelToken: source.token });
  16.   },
  17.   delete: <T>(url: string, config?: AxiosRequestConfig): Promise<T> => {
  18.     const source = axios.CancelToken.source();
  19.     cancelTokenMap.set(url, source);
  20.     return instance.delete(url, { ...config, cancelToken: source.token });
  21.   },
  22.   // 取消指定请求
  23.   cancelRequest: (url: string) => {
  24.     const source = cancelTokenMap.get(url);
  25.     if (source) {
  26.       source.cancel(`Request canceled: ${url}`);
  27.       cancelTokenMap.delete(url);
  28.     }
  29.   },
  30.   // 取消所有请求
  31.   cancelAllRequests: () => {
  32.     cancelTokenMap.forEach((source, url) => {
  33.       source.cancel(`Request canceled: ${url}`);
  34.       cancelTokenMap.delete(url);
  35.     });
  36.   },
  37. };
复制代码


2. 请求取消的实现原理

2.1 CancelToken 的作用


2.2 请求取消的流程


3. 使用场景

3.1 取消重复请求

当用户快速点击按钮多次触发雷同的请求时,可以通过 cancelRequest 方法取消之前的请求,只保存最后一次请求。
  1. http.get('/api/data')
  2.   .then((data) => console.log(data))
  3.   .catch((error) => {
  4.     if (axios.isCancel(error)) {
  5.       console.log('Request canceled:', error.message);
  6.     } else {
  7.       console.error('Error:', error);
  8.     }
  9.   });
  10. // 取消之前的请求
  11. http.cancelRequest('/api/data');
复制代码
3.2 页面跳转时取消请求

当用户跳转到其他页面时,可以通过 cancelAllRequests 方法取消全部未完成的请求,制止无效请求占用资源。
  1. window.addEventListener('beforeunload', () => {
  2.   http.cancelAllRequests();
  3. });
复制代码

完备代码

  1. import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, CancelTokenSource } from 'axios';// 创建axios实例const instance: AxiosInstance = axios.create({
  2.   baseURL: import.meta.env.VITE_API_BASE_URL,
  3.   timeout: 10000,
  4.   headers: {
  5.     'Content-Type': 'application/json',
  6.   },
  7. });
  8. // 创建一个Map来存储取消令牌const cancelTokenMap = new Map<string, CancelTokenSource>();
  9. // 请求拦截器instance.interceptors.request.use(  (config) => {    // 在这里可以添加token等全局请求头    const token = localStorage.getItem('token');    if (token) {      config.headers = config.headers || {};      config.headers.Authorization = `Bearer ${token}`;    }    return config;  },  (error) => {    return Promise.reject(error);  });// 响应拦截器instance.interceptors.response.use(  (response: AxiosResponse) => {    // 清理已完成的请求记载    const url = response.config.url;    if (url && cancelTokenMap.has(url)) {      cancelTokenMap.delete(url);    }    // 在这里处置惩罚全局响应逻辑    if (response.data.code !== 0) {      return Promise.reject(response.data);    }    return response.data;  },  (error) => {    // 清理失败的请求记载    const url = error.config?.url;    if (url && cancelTokenMap.has(url)) {      cancelTokenMap.delete(url);    }    // 在这里处置惩罚全局错误    if (error.response?.status === 401) {      // 处置惩罚未授权      window.location.href = '/login';    }    return Promise.reject(error);  });// 封装请求方法const http = {  get: <T>(url: string, config?: AxiosRequestConfig): Promise<T> => {    const source = axios.CancelToken.source();    cancelTokenMap.set(url, source);    return instance.get(url, { ...config, cancelToken: source.token });  },  post: <T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> => {    const source = axios.CancelToken.source();    cancelTokenMap.set(url, source);    return instance.post(url, data, { ...config, cancelToken: source.token });  },  put: <T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> => {    const source = axios.CancelToken.source();    cancelTokenMap.set(url, source);    return instance.put(url, data, { ...config, cancelToken: source.token });  },  delete: <T>(url: string, config?: AxiosRequestConfig): Promise<T> => {    const source = axios.CancelToken.source();    cancelTokenMap.set(url, source);    return instance.delete(url, { ...config, cancelToken: source.token });  },  // 添加取消请求的方法  // http.cancelRequest('/api/some-endpoint');  cancelRequest: (url: string) => {    const source = cancelTokenMap.get(url);    if (source) {      source.cancel(`Request canceled: ${url}`);      cancelTokenMap.delete(url);    }  },  // 取消全部请求  cancelAllRequests: () => {    cancelTokenMap.forEach((source, url) => {      source.cancel(`Request canceled: ${url}`);      cancelTokenMap.delete(url);    });  },};export default http;
复制代码
4. 总结

通过二次封装 Axios,我们实现了一个功能强盛且易于使用的 HTTP 客户端。它不光支持全局的请求和响应拦截,还提供了机动的请求取消功能,适用于多种场景。盼望本文能帮助你更好地理解和使用 Axios 的请求取消功能。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 IT评测·应用市场-qidao123.com (https://dis.qidao123.com/) Powered by Discuz! X3.4