封装全局请求节流

116 阅读3分钟

为了实现全局请求的截流(throttling),我们可以通过一个中间件或者拦截器来处理所有的 HTTP 请求,确保在一定时间间隔内只发送一次请求。对于 Vue 项目来说,通常会使用 axios 或者类似的 HTTP 客户端库来进行网络请求。我们将基于 axios 来创建一个简单的全局请求截流实例。

实现思路

  1. 定义一个 Map:用来存储每个请求 URL 和最后一次成功发起的时间戳。
  2. 设置一个时间窗口:在这个时间段内不允许重复发起相同的请求。
  3. 创建一个 Axios 拦截器:在请求发送之前检查是否满足时间窗口的要求。
  4. 处理异常情况:比如如果请求被取消或失败了,应该允许重新尝试。

全局请求截流实例代码

import axios from 'axios';
import { throttle } from 'lodash'; // 如果你想用 lodash 的 throttle 函数也可以

// 创建一个新的 axios 实例
const http = axios.create({
  baseURL: 'https://api.example.com', // 你的 API 基础地址
  timeout: 5000, // 请求超时时间
});

// 存储最近一次请求的时间戳
const requestTimestamps = new Map();

// 时间窗口 (毫秒)
const THROTTLE_WINDOW = 1000; // 例如设置为 1 秒

// 截流函数
function throttleRequest(url) {
  const now = Date.now();
  if (requestTimestamps.has(url)) {
    const lastTime = requestTimestamps.get(url);
    if (now - lastTime < THROTTLE_WINDOW) {
      console.log(`Throttling request to ${url}`);
      return false;
    }
  }
  requestTimestamps.set(url, now);
  return true;
}

// 添加请求拦截器
http.interceptors.request.use(
  config => {
    // 检查是否需要截流
    if (!throttleRequest(config.url)) {
      return Promise.reject(new Error('Request throttled'));
    }

    // 如果通过了截流检查,则继续执行请求
    return config;
  },
  error => {
    // 请求错误处理
    return Promise.reject(error);
  }
);

// 添加响应拦截器
http.interceptors.response.use(
  response => {
    // 成功响应后更新时间戳
    if (response.config.url) {
      requestTimestamps.set(response.config.url, Date.now());
    }
    return response;
  },
  error => {
    // 处理响应错误
    if (error.response && error.response.config.url) {
      // 如果请求失败了,允许立即重试
      requestTimestamps.delete(error.response.config.url);
    }
    return Promise.reject(error);
  }
);

export default http;

使用 Lodash 的 throttle 方法

如果你更倾向于使用像 Lodash 这样的库提供的 throttle 函数,可以这样改写:

import axios from 'axios';
import { throttle } from 'lodash';

const http = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 5000,
});

// 使用 lodash 的 throttle 函数包装 axios 请求方法
http.request = throttle(http.request, THROTTLE_WINDOW, { trailing: false });

export default http;

这种方法更加简洁,但需要注意的是,Lodash 的 throttle 是针对函数调用的节流,它并不直接适用于我们的场景,因为我们需要根据不同的 URL 来做节流控制。因此,第一种方法是更适合这个需求的解决方案。

注意事项

  • 在实际应用中,你可能还需要考虑更多的细节,比如如何处理 POST 请求中的不同参数组合,因为它们可能会被视为不同的请求。
  • 如果你需要支持更复杂的逻辑,比如根据不同的 HTTP 方法、查询参数等进行更细粒度的截流控制,那么你可能需要对上面的代码进一步扩展。
  • 确保你不会意外地阻止了必要的请求,尤其是在用户交互频繁的情况下,如搜索框输入时触发的自动补全请求。