axios 取消上次重复请求

在实际开发中,可能会遇到同一个接口被多次调用的情况(例如用户快速点击按钮或页面频繁刷新)。为了避免重复请求浪费资源,可以通过以下设计思路实现取消重复请求。

1.实现思路
  1. 唯一标识请求

    为每个请求生成一个唯一标识符(requestKey),通常由请求的 method 和 url 组成。如果需要更精确,可以将 params 或 data 也纳入标识符。

  2. 存储请求

    使用一个数据结构(如 Map)来存储当前正在进行的请求及其对应的 AbortController 实例。

  3. 取消重复请求

    在发送新请求时,检查 Map 中是否已经存在相同的 requestKey。如果存在,调用 AbortController.abort() 取消上一个请求,并从 Map 中移除。如果不存在,则将当前请求的 AbortController 存入 Map。

  4. 移除已完成的请求

    在请求完成或失败时,从 Map 中移除对应的 requestKey。

2.实现步骤
  1. 创建 Map 存储请求
    使用 Map 数据结构存储请求的唯一标识符和对应的 AbortController。
js 复制代码
const pendingRequests = new Map<string, AbortController>();
  1. 生成请求的唯一标识符
    定义一个函数,根据请求的 method 和 url 生成唯一标识符。
js 复制代码
const getRequestKey = (config: AxiosRequestConfig): string => {
  return `${config.method}:${config.url}`;
};
  1. 请求拦截器
    在请求拦截器中:检查 Map 中是否存在相同的 requestKey。如果存在,取消上一个请求。
    如果不存在则为当前请求创建一个新的 AbortController,并存入 Map。
js 复制代码
axiosInstance.interceptors.request.use((config: AxiosRequestConfig) => {
  const requestKey = getRequestKey(config);

  // 如果存在相同的请求,则取消上一次请求
  if (pendingRequests.has(requestKey)) {
    const controller = pendingRequests.get(requestKey);
    controller?.abort(); // 取消上次请求
    pendingRequests.delete(requestKey); // 从 Map 中移除
  }

  // 为当前请求创建一个新的 AbortController
  const controller = new AbortController();
  config.signal = controller.signal;

  // 将当前请求存储到 Map 中
  pendingRequests.set(requestKey, controller);

  return config;
});
  1. 响应拦截器
    在响应拦截器中:请求完成后,从 Map 中移除对应的 requestKey。
js 复制代码
axiosInstance.interceptors.response.use(
  (response: AxiosResponse) => {
    const requestKey = getRequestKey(response.config);
    pendingRequests.delete(requestKey); // 请求完成后移除
    return response.data;
  },
  (error) => {
    if (axios.isCancel(error)) {
      console.warn("Request canceled:", error.message);
    } else {
      const requestKey = getRequestKey(error.config);
      pendingRequests.delete(requestKey); // 请求完成后移除
      console.error("API Error:", error.response?.data || error.message);
    }
    return Promise.reject(error);
  }
);
  1. 完整代码实现
js 复制代码
import axios, { AxiosRequestConfig, AxiosResponse } from "axios";

// 用于存储请求的 Map
const pendingRequests = new Map<string, AbortController>();

// 生成请求的唯一标识
const getRequestKey = (config: AxiosRequestConfig): string => {
  return `${config.method}:${config.url}`;
};

// 创建 Axios 实例
const axiosInstance = axios.create({
  baseURL: import.meta.env.VITE_BASE_URL, // 替换为你的 API 基础 URL
  timeout: 50000, // 请求超时时间
  headers: {
    "Content-Type": "application/json",
  },
});

// 请求拦截器
axiosInstance.interceptors.request.use((config: AxiosRequestConfig) => {
  const requestKey = getRequestKey(config);

  // 如果存在相同的请求,则取消上一次请求
  if (pendingRequests.has(requestKey)) {
    const controller = pendingRequests.get(requestKey);
    controller?.abort(); // 取消上次请求
    pendingRequests.delete(requestKey); // 从 Map 中移除
  }

  // 为当前请求创建一个新的 AbortController
  const controller = new AbortController();
  config.signal = controller.signal;

  // 将当前请求存储到 Map 中
  pendingRequests.set(requestKey, controller);

  return config;
});

// 响应拦截器
axiosInstance.interceptors.response.use(
  (response: AxiosResponse) => {
    const requestKey = getRequestKey(response.config);
    pendingRequests.delete(requestKey); // 请求完成后移除
    return response.data;
  },
  (error) => {
    if (axios.isCancel(error)) {
      console.warn("Request canceled:", error.message);
    } else {
      const requestKey = getRequestKey(error.config);
      pendingRequests.delete(requestKey); // 请求完成后移除
      console.error("API Error:", error.response?.data || error.message);
    }
    return Promise.reject(error);
  }
);

export default axiosInstance;
相关推荐
爱上好庆祝4 小时前
学习js的第五天
前端·css·学习·html·css3·js
Python私教6 小时前
Pure-Admin-Thin 深度解析:完整版和精简版到底怎么选?
vue.js·人工智能·开源
ayqy贾杰8 小时前
Cursor SDK发布!开发者可直接搬走其内核
前端·vue.js·面试
李白的天不白9 小时前
vue 数据格式问题
前端·vue.js·windows
小白蒋博客9 小时前
【ai开发段永平投资理财的知识图谱网站】第一天:搭 Vite + Vue 项目,跑通 Hello World
vue.js·人工智能·trae
@yanyu66619 小时前
登录注册功能-明文
vue.js·springboot
cn_mengbei1 天前
用React Native开发OpenHarmony应用:Reanimated共享元素过渡
javascript·react native·react.js
滕青山1 天前
在线PDF拆分工具核心JS实现
前端·javascript·vue.js
捉鸭子1 天前
某音a_bogus vmp逆向
爬虫·python·web安全·node.js·js
We་ct1 天前
React 性能优化精讲
前端·javascript·react.js·性能优化·前端框架·html·浏览器