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
  • 如不存在,执行新请求并缓存
相关推荐
JustHappy几秒前
「chrome extensions🛠️」我写了一个超级简单的浏览器插件Vue开发模板
前端·javascript·github
Loo国昌2 分钟前
Vue 3 前端工程化:架构、核心原理与生产实践
前端·vue.js·架构
sg_knight4 分钟前
拥抱未来:ECMAScript Modules (ESM) 深度解析
开发语言·前端·javascript·vue·ecmascript·web·esm
LYFlied5 分钟前
【每日算法】LeetCode 17. 电话号码的字母组合
前端·算法·leetcode·面试·职场和发展
开发者小天5 分钟前
react中useEffect的用法,以及订阅模式的原理
前端·react.js·前端框架
前端白袍25 分钟前
Vue:如何实现一个具有复制功能的文字按钮?
前端·javascript·vue.js
new code Boy1 小时前
escape谨慎使用
前端·javascript·vue.js
奶球不是球1 小时前
elementplus组件中el-calendar组件自定义日期单元格内容及样式
javascript·css·css3
叠叠乐1 小时前
robot_state_publisher 参数
java·前端·算法
Kiri霧1 小时前
Range循环和切片
前端·后端·学习·golang