Axios 取消请求

398 阅读2分钟

接口请求封装

对于axios的接口请求基本已经是很成熟的方案了,接下来的代码是使用AbortController取消接口请求的一个简单案例供大家参考。

使用pinia来保存接口的唯一标识用以之后的取消功能

import { defineStore } from "pinia";
import { store } from "@/store";

interface RequestController {
  key: string;
  controller: AbortController;
}

const useCancelRequestsStore = defineStore("requests", {
  state: () => ({
    controllers: new Map<string, RequestController>()
  }),
  actions: {
    /**
     * 添加请求,并返回相应的 AbortSignal
     *
     * @param key 请求的唯一标识符
     * @returns 如果请求已存在,则返回 undefined;否则返回相应的 AbortSignal
     */
    addRequest(key: string): AbortSignal | undefined {
      // 如果已经存在该key的请求,则输出警告信息
      if (this.controllers.has(key)) {
        console.warn(`Request with key ${key} already exists.`);
        // 返回undefined,或者根据需求可以抛出异常
        return undefined; // 或者可以抛出异常,取决于你的需求
      }

      // 创建一个新的AbortController实例
      const controller = new AbortController();
      // 将key和controller对象存入controllers集合中
      this.controllers.set(key, { key, controller });
      // 返回controller的signal对象
      return controller.signal;
    },
    /**
     * 删除已完成的请求,防止map中存在不需要取消的请求
     *
     * @param key 请求的key值
     */
    delRequest(key: string) {
      // 根据给定的 key 从 controllers 中删除对应的请求控制器
      this.controllers.delete(key);
    },
    /**
     * 取消请求
     *
     * @param key 请求的标识
     */
    cancelRequest(key: string) {
      // 获取指定 key 的请求控制器
      const entry = this.controllers.get(key);
      if (entry) {
        try {
          // 调用请求控制器的 abort 方法取消请求
          entry.controller.abort();
          // 输出成功取消请求的信息
          console.log(`Request with key ${key} was successfully aborted.`);
          // 从控制器集合中删除已取消的请求控制器
          this.controllers.delete(key);
        } catch (error) {
          // 输出取消请求失败的信息及错误原因
          console.error(`Failed to abort request with key ${key}:`, error);
        }
      } else {
        // 输出没有找到对应 key 的请求信息
        console.warn(`No request found with key ${key} to abort.`);
      }
    },
    /**
     * 取消所有请求
     *
     * 遍历所有的请求控制器,并逐个取消它们。
     * 取消请求后,在控制台输出一条消息,指示已取消该请求。
     * 如果取消请求时发生错误,则在控制台输出一条错误消息,指示已取消失败。
     * 清除所有请求控制器,并在控制台输出一条消息,指示所有请求已取消。
     */
    cancelAllRequests() {
      // 遍历controllers数组
      this.controllers.forEach((entry, key) => {
        try {
          // 调用每个entry的controller的abort方法取消请求
          entry.controller.abort();
          // 输出日志,表示已取消指定key的请求
          console.log(
            `Request with key ${key} was aborted as part of cancelAllRequests.`
          );
        } catch (error) {
          // 如果取消请求时发生错误,输出错误日志
          console.error(
            `Failed to abort request with key ${key} during cancelAllRequests:`,
            error
          );
        }
      });
      // 清空controllers数组
      this.controllers.clear();
      // 输出日志,表示所有请求已取消
      console.log("All requests have been cancelled.");
    }
  }
});

export function useCancelRequestsHook() {
  return useCancelRequestsStore(store);
}


在公共的request封装中引用store

  /**
   * 设置http请求拦截器
   *
   * @returns 无返回值
   */
  private httpInterceptorsRequest(): void {
    PureHttp.axiosInstance.interceptors.request.use(
      async (config: PureHttpRequestConfig): Promise<any> => {
        /**
         * 添加取消请求功能
         */
        if (!config.signal && config.requestId) {
          // 支持用户通过业务侧使用,方便单独清除页面中的请求
          const signal = useCancelRequestsHook().addRequest(config.requestId);
          config.signal = signal;
        }
        // ... 省略
      },
      error => {
        return Promise.reject(error);
      }
    );
  }
  /**
   * 发起网络请求
   *
   * @param method 请求方法,例如:'get', 'post'
   * @param url 请求地址
   * @param param 请求参数
   * @param axiosConfig 额外的Axios配置
   * @returns 返回请求结果的Promise
   */
  public request<T>(
    method: RequestMethods,
    url: string,
    param?: AxiosRequestConfig,
    axiosConfig?: PureHttpRequestConfig
  ): Promise<T> {
    // 定义一个唯一Id用以释放store中存储的标识
    const requestId = uuid(64);
    const config = {
      method,
      url,
      requestId,
      ...param,
      ...axiosConfig
    } as PureHttpRequestConfig;

    // 创建一个新的Promise对象,用于处理异步请求
    // 单独处理自定义请求/响应回调
    return new Promise((resolve, reject) => {
      PureHttp.axiosInstance
        .request(config)
        // 请求成功时,将响应数据通过resolve返回
        .then((response: undefined) => {
          resolve(response);
        })
        // 请求失败时,将错误信息通过reject返回
        .catch(error => {
          reject(error);
        })
        // 请求完成后执行,无论成功或失败
        .finally(() => {
          /* 接口请求完毕,清除取消标识 */
          useCancelRequestsHook().delRequest(config.requestId);
        });
    });
  }
}