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
  • 如不存在,执行新请求并缓存
相关推荐
Revolution6138 分钟前
React 组件重新渲染时,到底重新执行了什么
前端·react.js·面试
用户2181697049302 小时前
Flutter(四)Dart语法 空安全 运算符 流程控制
前端
许彰午2 小时前
政务督办的分合模式:主办协办的并发审批
前端·javascript·政务
用户69371750013842 小时前
AI时代,程序员该往哪走?
前端·后端
ttwuai2 小时前
GoFrame 后台日志清空失败:无 WHERE 删除为什么被拦住
前端·golang
易筋紫容2 小时前
创建型模式:对象的诞生艺术
开发语言·前端·javascript
半句唐诗3 小时前
我是如何通过 Access Token 成功发布第一个 npm 包的
前端·npm·node.js
程序员黑豆3 小时前
鸿蒙应用开发:@Provider 与 @Consumer 跨组件双向同步详解
前端·harmonyos
paopaokaka_luck3 小时前
基于springboot3+vue3的智能文库平台(AI智能搜索、AI智能汇总、实时在线状态展示、多格式文档预览与富文本编辑、Echarts图形化分析)
前端·网络·spring boot·网络协议·echarts
牧艺3 小时前
cos-design PhotoAlbum:用 CSS 3D 做一个「能翻页」的实体相册
前端·css·交互设计