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
  • 如不存在,执行新请求并缓存
相关推荐
hj5914_前端新手2 小时前
javascript基础- 函数中 this 指向、call、apply、bind
前端·javascript
薛定谔的算法2 小时前
低代码编辑器项目设计与实现:以JSON为核心的数据驱动架构
前端·react.js·前端框架
Hilaku2 小时前
都2025年了,我们还有必要为了兼容性,去写那么多polyfill吗?
前端·javascript·css
yangcode2 小时前
iOS 苹果内购 Storekit 2
前端
LuckySusu2 小时前
【js篇】JavaScript 原型修改 vs 重写:深入理解 constructor的指向问题
前端·javascript
LuckySusu2 小时前
【js篇】如何准确获取对象自身的属性?hasOwnProperty深度解析
前端·javascript
LuckySusu2 小时前
【js篇】深入理解 JavaScript 作用域与作用域链
前端·javascript
LuckySusu2 小时前
【js篇】call() 与 apply()深度对比
前端·javascript
LuckySusu2 小时前
【js篇】addEventListener()方法的参数和使用
前端·javascript
该用户已不存在2 小时前
6个值得收藏的.NET ORM 框架
前端·后端·.net