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;
相关推荐
计算机学姐10 分钟前
基于SpringBoot的汉服租赁系统【颜色尺码套装+个性化推荐算法+数据可视化统计】
java·vue.js·spring boot·后端·mysql·信息可视化·推荐算法
+VX:Fegn089511 分钟前
计算机毕业设计|基于springboot + vue建筑材料管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
雪碧聊技术19 分钟前
ElementPlus徽章组件:展示日期面板每天未完成的待办数量
vue.js·日期选择器·elementplus·el-badge徽章组件
哈__1 小时前
从入门小白到精通,玩转 React Native 鸿蒙跨平台开发:TouchableOpacity 触摸反馈组件
react native·react.js·harmonyos
古茗前端团队1 小时前
视频播放弱网提示实现
react.js
哈__1 小时前
入门小白到精通,玩转 React Native 鸿蒙跨平台开发:Button 按钮组件与点击事件
react native·react.js·harmonyos
哈__1 小时前
React Native 鸿蒙开发:内置 Share 模块实现无配置社交分享
javascript·react native·react.js
沐墨染2 小时前
敏感词智能检索前端组件设计:树形组织过滤与多维数据分析
前端·javascript·vue.js·ui·数据挖掘·数据分析
xkxnq2 小时前
第二阶段:Vue 组件化开发(第 18天)
前端·javascript·vue.js
怕浪猫2 小时前
React从入门到出门 第五章 React Router 配置与原理初探
前端·javascript·react.js