JavaScript 实现防止重复网络请求的拦截方案

作者:青柠时间:2026-10-24 07:36:50浏览:415

本文介绍了一种基于 JavaScript 和 Axios 防止网络重复请求的实现方案。通过拦截请求配置,利用 Set 集合构建请求队列,在发送前校验 URL、方法及参数组合。若队列中已存在相同请求则取消当前请求,响应完成后自动清理队列。该方案解决了页面抖动、路由切换后无效请求残留等问题,无需使用复杂的 CancelToken,代码简洁且易于集成。

前言

在 Web 开发过程中,接口重复请求是一个常见且棘手的问题。重复的网络请求会导致页面多次更新,引发界面抖动,严重影响用户体验。例如,当用户在前一个请求尚未响应完成时就切换了路由,这些未完成的请求会一直挂起,直到响应返回才中止。无论是从用户体验的角度,还是从业务逻辑的严谨性考虑,及时取消无用的重复请求都是必须处理的关键环节。

实现思路

前言

核心逻辑主要包含以下步骤: 1. 在发送网络请求之前,先对当前请求的唯一标识进行拦截,该标识由 URL、请求方法及参数共同组成; 2. 建立一个请求队列,用于存储当前正在进行的请求标识; 3. 每次发起请求时,检查请求队列中是否已存在相同的请求标识; 4. 如果队列中已存在该标识,则取消当前新发起的请求; 5. 如果队列中不存在该标识,则正常发送请求。当请求数据成功返回后,从请求队列中移除对应的请求标识。

1. 常规接口调用方式

请求接口文件


import { http } from '@/plugin/axios'; // 导入请求接口 http

// 初始化
export function getInit(params) {
  return http({
    method: 'get',
    url: '/xxx/xxx/xx',
    params,
  });
}

关键在于执行 HTTP 方法时进行逻辑处理。在执行 http 函数时,可以获取到完整的请求配置 config,并返回 Promise 对象。

2. 基于 Axios 的封装思路

axios.js配置文件


import axios from 'axios';
import { httpRequest, completeRequest } from './options'; // 这里就是我们要实现的逻辑文件

// 里面做一些请求拦截,响应拦截操作 具体查看axios文档
const service = axios.create({
  baseURL: 'xxx/xxx',
});

// 请求拦截器
service.interceptors.request.use(config => {}, error => {})

// 响应拦截器
service.interceptors.response.use(response => {
 completeRequest(response); // 2.响应请求回来执行
}, error => {
 
})

export function http(config) { // => 这里config就是传递的请求配置参数
  return httpRequest(config, service); // + 1.在这里做一些逻辑操作
}

3. 防止重复请求的核心配置

options.js (1)在发送请求前,检查请求队列中是否已存在当前请求(通过 URL 地址判断)。

  • 若请求队列中已存在当前 URL 地址,则取消当前请求,并返回 Promise.reject 以表示失败。
  • 若请求队列中不存在当前请求,则正常发送请求。

/**
 * 职责: 防止重复的网络请求
 *
 */

let list = new Set(); // 1.请求队列

// 合并 方法 参数 url地址
function getUrl(config = {}) {
 // get请求 params参数 post请求 data参数, baseURL
 const { url, method, params, data, baseURL = '' } = config;
 const urlVal = url.replace(baseURL, '');
 return `${urlVal}?${method === 'get' ? getformatObjVal(params) : getformatObjVal(data)}`;
}

// 处理 url地址 
const getformatObjVal = (obj) => {
 obj = typeof obj === 'string' ? JSON.parse(`${obj}`) : obj;
 var str = [];
 for (let p in obj) {
  if (obj.hasOwnProperty(p) && p !== '_t') {
   var item = obj[p] === null ? '' : obj[p]; // 处理null
   str.push(encodeURIComponent(p) + '=' + encodeURIComponent(item));
  }
 }
 return str.join('&');
}

// 2.请求方法
export function httpRequest(config = {}, axios) {
 const url = getUrl(config); //3. 这里我们获取到了URL地址

 if (list.has(url)) { // 4.查看请求队列是否有当前url地址
  return Promise.reject('In the request'); // 5.在请求队列里面 取消当前请求, 返回Promise失败结果
 }
 
 // 6. 请求队列没有当前url地址 发送请求并把url地址存入请求队列里
 list.add(url);
 return Promise.resolve(axios); 
}

(2)当请求响应返回后,从请求队列中删除当前 URL 地址,以便下一次相同的请求可以正常发送。


// 请求响应回来执行这个函数
export function completeRequest(response = {}) {
 const { config } = response; // 1.response里面config能拿到配置参数
 const url = getUrl(config); // 2.获取url地址 
 if (list.has(url)) {
  list.delete(url); // 3.删除请求队列中的当前请求url地址
 }
}

axios.js


import axios from 'axios';
import { httpRequest, completeRequest } from './options'; // 防止重复请求

const service = axios.create({
  baseURL: 'xxx/xxx',
});

// 请求拦截器
service.interceptors.request.use(config => {}, error => {})

// 响应拦截器
service.interceptors.response.use(response => {
 completeRequest(response); // 2.响应请求回来执行 +
}, error => {
 
})


// 导出请求
export function http(config) {
  return httpRequest(config, service); // 1.发送请求前执行
}

至此,防止重复网络请求的基本功能已实现。但还需处理响应异常的情况:如果请求发生异常,必须清除请求队列中对应的 URL 地址。否则,后续相同的请求会被直接取消。这里提供一个简单的方法,即清空整个请求队列,开发者可根据实际业务场景进行更精细的控制。


/**
 * 清空所有请求队列
 */
export function clearRequestList() {
 list = new Set(); // 这里我就直接清空了
}

完整http.js文件


import axios from 'axios';
import { httpRequest, completeRequest, clearRequestList } from './options'; // 防止重复请求 +

const service = axios.create({
  baseURL: 'xxx/xxx',
});

// 请求拦截器
service.interceptors.request.use(config => {}, error => {})

// 响应拦截器
service.interceptors.response.use(response => {
 completeRequest(response); // 2.响应请求回来执行
}, error => {
 clearRequestList(); // + 
})


// 导出请求
export function http(config) {
  return httpRequest(config, service); // 1.发送请求前执行
}

完整options.js


/**
 * 职责: 防止重复的网络请求
 *
 */

let list = new Set(); // 1.请求队列

// 合并 方法 参数 url地址
function getUrl(config = {}) {
 // get请求 params参数 post请求 data参数, baseURL
 const { url, method, params, baseURL = '' } = config;
 const urlVal = url.replace(baseURL, '');
 return `${urlVal}?${method === 'get' ? getformatObjVal(params) : 'post'}`;
}

// 处理 url地址 
const getformatObjVal = (obj) => {
 obj = typeof obj === 'string' ? JSON.parse(`${obj}`) : obj;
 var str = [];
 for (let p in obj) {
  if (obj.hasOwnProperty(p) && p !== '_t') {
   var item = obj[p] === null ? '' : obj[p]; // 处理null
   str.push(encodeURIComponent(p) + '=' + encodeURIComponent(item));
  }
 }
 return str.join('&');
}

// 2.请求方法
export function httpRequest(config = {}, axios) {
 const url = getUrl(config); //3. 这里我们获取到了URL地址

 if (list.has(url)) { // 4.查看请求队列是否有当前url地址
  return Promise.reject('In the request'); // 5.在请求队列里面 取消当前请求, 返回Promise失败结果
 }

 // 6. 请求队列没有当前url地址 发送请求并把url地址存入请求队列里
 list.add(url);
 return Promise.resolve(axios);
}


/**
 * 请求响应回来执行这个函数
 */
export function completeRequest(response = {}) {
 const { config } = response; // 1.response里面config能拿到配置参数
 const url = getUrl(config); // 2.获取url地址 
 list.has(url) && list.delete(url); // 3.删除请求队列中的当前请求url地址
}

/**
 * 清空所有请求队列
 */
export function clearRequestList(error) {
 // error 可以获取到配置, 做一些操作。
 list = new Set(); // 这里我就直接清空了
}

以上即为防止网络重复请求的实现方式。此前曾尝试使用 Axios 中的 CancelToken 来取消请求,但发现存在一些局限性。

  1. 首先,需要配置请求文件,这种方式不够友好,且在团队开发中配置较为繁琐。
  2. 其次,需要为每个请求单独配置 CancelToken。具体使用有两个方法,详细可参考官方文档。

到此,关于 JavaScript 如何实现防止重复网络请求的示例介绍完毕。更多相关 JavaScript 防止重复网络请求的内容,请搜索本站以前的文章或继续浏览下面的相关文章。希望大家以后多多支持本站!

作者最新文章