axios重复请求解决方案

背景

在平时项目开发中,由于历史问题,可能存在很多接口重复请求数据,带来以下问题:

  • 网络资源浪费、增加服务器负载
  • 页面组件重复渲染,出现闪动现象,降低用户体验

解决方案一

重构业务代码,但由于业务逻辑过多,一旦修改,容易出现线上bug,风险较高,不可取

解决方案二(最终方案)

前端请求都经过axios,在axios出添加拦截逻辑,如果在1s内发出多个相同请求,则默认只放第一个通过,其他的复用第一个的结果,可以采用axios的adapter来实现

使用方式

php 复制代码
// ~request.ts
import axios, { AxiosAdapter } from 'axios';
import { createThrottleAdapter } from '@/utils/axiosThrottleAdapter';

const client = axios.create({
  timeout: 30000,
  baseURL: getAPIBaseUrl(),

  // adapter使用方式
  adapter: createThrottleAdapter(axios.defaults.adapter as AxiosAdapter, {
    threshold: 1000,
  }),
});
...

具体实现

typescript 复制代码
// ~@/utils/axiosThrottleAdapter
import { AxiosAdapter, AxiosRequestConfig } from 'axios';

interface ThrottleAdapterOptions {
  /**
   * 节流间隔时间(毫秒)
   */
  threshold?: number;
}

interface RequestCacheItem {
  timestamp: number;
  promise: Promise<any>;
}

/**
 * 生成请求缓存键
 * @param config axios请求配置
 * @returns 缓存键
 */
const getCacheKey = (config: AxiosRequestConfig): string => {
  const { method = 'get', url = '', params, data } = config;
  const queryKey = params ? JSON.stringify(params) : '';
  const bodyKey = data ? JSON.stringify(data) : '';
  return `${method}:${url}:${queryKey}:${bodyKey}`;
};

/**
 * 创建支持所有请求类型节流的适配器
 * @param adapter 原始适配器
 * @param options 节流选项
 * @returns 增强后的适配器
 */
export const createThrottleAdapter = (adapter: AxiosAdapter, options: ThrottleAdapterOptions = {}): AxiosAdapter => {
  const { threshold = 1000 } = options;
  const requestCache: Record<string, RequestCacheItem> = {};

  return (config: AxiosRequestConfig) => {
    // 如果是OPTIONS请求或请求配置中明确禁用了节流,直接使用原始适配器
    const method = (config.method || 'get').toLowerCase();
    if (method === 'options' || config.throttle === false) {
      return adapter(config);
    }

    const cacheKey = getCacheKey(config);
    const now = Date.now();

    // 清理过期的缓存
    Object.keys(requestCache).forEach((key) => {
      const { timestamp } = requestCache[key];
      if (now - timestamp > threshold) {
        delete requestCache[key];
      }
    });

    // 检查缓存中是否存在未过期的请求
    if (requestCache[cacheKey] && now - requestCache[cacheKey].timestamp <= threshold) {
      return requestCache[cacheKey].promise;
    }

    // 执行请求
    const promise = adapter(config);

    // 更新缓存
    requestCache[cacheKey] = {
      timestamp: now,
      promise,
    };

    return promise;
  };
};

// 扩展AxiosRequestConfig类型
declare module 'axios' {
  interface AxiosRequestConfig {
    /**
     * 是否禁用请求节流
     */
    throttle?: boolean;
  }
}

核心逻辑梳理

  1. 跳过节流的情况:
  • OPTIONS 请求不进行节流
  • 请求配置中 throttle: false 时不进行节流
  1. 缓存管理:
  • 生成当前请求的缓存键
  • 清理过期缓存项
  • 检查是否存在相同的未过期请求
  • 如存在,返回缓存的请求Promise
  • 如不存在,执行新请求并缓存
相关推荐
酉鬼女又兒6 分钟前
零基础快速入门前端Web存储(sessionStorage & localStorage)知识点详解与蓝桥杯考点应用(可用于备赛蓝桥杯Web应用开发)
开发语言·前端·javascript·职场和发展·蓝桥杯·html
DanCheOo11 分钟前
# 从"会用 AI"到"架构 AI":高级前端的认知升级
前端·ai编程
社恐的下水道蟑螂14 分钟前
前端面试必问 Git 通关指南:常用命令速查 + merge/rebase 深度辨析,看完再也不慌
前端·git·面试
angerdream21 分钟前
最新版vue3+TypeScript开发入门到实战教程之组件通信之二
javascript·vue.js
小只笨笨狗~22 分钟前
解决objectSpanMethod与expand共存时展开后表格错位问题
开发语言·javascript·ecmascript
None32122 分钟前
NestJS 流式文件上传实践:从 Multer 到 Busboy 的进阶之路
前端·后端
海浪浪24 分钟前
Symbol 产生的背景以及应用场景
前端·javascript
DROm RAPS33 分钟前
十七:Spring Boot依赖 (2)-- spring-boot-starter-web 依赖详解
前端·spring boot·后端
OpenTiny社区34 分钟前
GenUI SDK v1.1.0 正式发布|全端体验革新,能力与稳定性进阶
前端·ai编程
IAUTOMOBILE36 分钟前
Code Marathon 项目源码解析与技术实践
java·前端·算法