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
  • 如不存在,执行新请求并缓存
相关推荐
一斤代码1 小时前
vue3 下载图片(标签内容可转图)
前端·javascript·vue
中微子1 小时前
React Router 源码深度剖析解决面试中的深层次问题
前端·react.js
光影少年2 小时前
从前端转go开发的学习路线
前端·学习·golang
中微子2 小时前
React Router 面试指南:从基础到实战
前端·react.js·前端框架
3Katrina2 小时前
深入理解 useLayoutEffect:解决 UI "闪烁"问题的利器
前端·javascript·面试
前端_学习之路3 小时前
React--Fiber 架构
前端·react.js·架构
coderlin_3 小时前
BI布局拖拽 (1) 深入react-gird-layout源码
android·javascript·react.js
伍哥的传说3 小时前
React 实现五子棋人机对战小游戏
前端·javascript·react.js·前端框架·node.js·ecmascript·js
qq_424409193 小时前
uniapp的app项目,某个页面长时间无操作,返回首页
前端·vue.js·uni-app
我在北京coding3 小时前
element el-table渲染二维对象数组
前端·javascript·vue.js