在Axios中防止重复提交可以通过以下两种主要方法实现: 使用CancelToken
取消重复请求 和 通过请求标识符过滤重复请求 。以下是具体实现方式及代码示例:
一、使用 CancelToken
取消重复请求
CancelToken
是Axios提供的内置机制,用于取消重复请求。其核心思想是为每个请求生成一个唯一的token
,并在发送新请求前检查是否已有相同请求在进行。
1. 基本实现步骤
-
创建
CancelToken
源使用
axios.CancelToken.source()
生成一个source
对象,包含token
和cancel
函数。 -
为每个请求设置
cancelToken
在发送请求前,检查是否已有相同请求的
token
,若存在则取消当前请求,否则将token
赋值给请求配置。 -
处理取消逻辑
在请求的
catch
块中,通过axios.isCancel(thrown)
判断请求是否被取消,并进行相应处理。
2. 代码示例
import axios from 'axios';
// 存储请求标识符的Map
const pendingRequests = new Map();
// 创建Axios实例(可选)
const instance = axios.create();
// 请求拦截器
instance.interceptors.request.use(config => {
// 生成唯一标识符(如URL+参数)
const requestId = `${config.url}${JSON.stringify(config.params)}`;
// 检查是否已有相同请求
if (pendingRequests.has(requestId)) {
// 取消当前请求
const cancel = config.cancelToken.source().cancel('Duplicate request detected');
pendingRequests.delete(requestId);
} else {
// 记录请求标识符
pendingRequests.set(requestId, true);
config.cancelToken = new axios.CancelToken((c) => {
cancel(`Request canceled by the user: ${requestId}`);
});
}
return config;
}, error => {
return Promise.reject(error);
});
// 响应拦截器(可选)
instance.interceptors.response.use(response => {
// 移除已完成请求的标识符
pendingRequests.delete(response.config.url + JSON.stringify(response.config.params));
return response;
}, error => {
return Promise.reject(error);
});
// 示例请求
instance.get('/api/data', { cancelToken: source.token })
.then(response => {
console.log(response.data);
})
.catch(error => {
if (axios.isCancel(error)) {
console.error(error.message);
} else {
console.error('Request failed:', error);
}
});
二、通过请求标识符过滤重复请求(高级方案)
1. 发布订阅模式实现
使用Set
存储未完成的请求标识符,通过EventEmitter
实现请求完成或失败时的通知机制,从而避免重复处理响应。
2. 代码示例
import axios from 'axios';
import EventEmitter from 'events';
// 存储未完成请求的Set
const pendingRequests = new Set();
const eventEmitter = new EventEmitter();
// 请求拦截器
axios.interceptors.request.use(config => {
const requestId = `${config.url}${JSON.stringify(config.params)}`;
if (pendingRequests.has(requestId)) {
// 发现重复请求,触发事件
eventEmitter.emit('request-duplicate', requestId);