axios全局做节流,解决多次点击导致多次请求接口

简介: 本文介绍了如何在Axios请求中实现全局节流,以防止用户快速多次点击导致重复发送相同请求的问题。

axios全局做节流,解决多次点击导致多次请求接口

1、收集请求的接口
2、判断当前接口上次请求时间
3、过滤过期判断的接口

收集请求的接口并判断是否可以继续请求

let reqList = []
// 默认maxTime 节流操作目的是为了方式用户手滑点击多次新增或者修改
let maxTime = 500
// 过滤请求事件
const stopRepeatRequest = (url, cancelFun) => {
   
    // url存在  更新 time
    if (reqList.length !== 0 && reqList.find(i => i.url === url)) {
   
        // 存在
        // 存在 并且 还不能进行下次点击
        let arr = reqList.filter(item => item.url === url && new Date().getTime() - item.time < maxTime)
        if (arr && arr.length !== 0) {
   
            cancelFun()
            return true
        } else {
   
            // 存在能进行下一次点击  能进行接口连接
            reqList = reqList.map(i => {
   
                if (i.url === url) {
   
                    i.time = new Date().getTime()
                }
                return i
            })
            return false
        }
    } else {
   
        // 不存在直接添加 能进行接口连接
        reqList.push({
   
            url,
            time: new Date().getTime()
        })
        return false
    }
}

过滤过期判断的接口

// 接口请求完成后清除
const allowRequest = () => {
   
    if (reqList.length) {
   
        // 只保留不能多次请求的接口
        reqList = reqList.filter(item => new Date().getTime() - item.time < maxTime)
    }
}
// 响应拦截
Ajax.interceptors.response.use(response => {
   
    // Do something before response is sent
    allowRequest()
    return response;
}, error => {
   
    // Do something with response error
    return Promise.reject(error);
});

全部代码

/*
 * @Descripttion: 
 * @version: 
 * @Author: ZhangJunQing
 * @Date: 2022-05-23 11:46:01
 * @LastEditors: ZhangJunQing
 * @LastEditTime: 2022-08-30 14:41:25
 */
import axios from 'axios';
import context from '@/main.js'
import {
    baseURL } from '@/Url'
let reqList = []
// 默认maxTime 节流操作目的是为了方式用户手滑点击多次新增或者修改
let maxTime = 500
const Ajax = axios.create({
   
    // 是否携带cookie
    withCredentials: true,
    baseURL,
    timeout: 50000
})
// 过滤请求事件
const stopRepeatRequest = (url, cancelFun) => {
   
    // 过滤可以多次一直请求的接口
    // 情况包括整个页面调用了两次整个接口 
    const filterList =[
        // 动态查询、展示列模板接口
        '/temp/query'
    ]
    if(filterList.includes(url)){
   
        return false
    }
    // url存在  更新 time
    if (reqList.length !== 0 && reqList.find(i => i.url === url)) {
   
        // 存在
        // 存在 并且 还不能进行下次点击
        let arr = reqList.filter(item => item.url === url && new Date().getTime() - item.time < maxTime)
        if (arr && arr.length !== 0) {
   
            cancelFun()
            return true
        } else {
   
            // 存在能进行下一次点击  能进行接口连接
            reqList = reqList.map(i => {
   
                if (i.url === url) {
   
                    i.time = new Date().getTime()
                }
                return i
            })
            return false
        }
    } else {
   
        // 不存在直接添加 能进行接口连接
        reqList.push({
   
            url,
            time: new Date().getTime()
        })
        return false
    }
}
// 接口请求完成后清除
const allowRequest = () => {
   
    if (reqList.length) {
   
        // 只保留不能多次请求的接口
        reqList = reqList.filter(item => new Date().getTime() - item.time < maxTime)
    }
}
// 请求拦截
Ajax.interceptors.request.use(config => {
   
    // 增加请求头
    config.headers["token"] = "xxxx"
    let cancelFun = null
    config.cancelToken = new axios.CancelToken(cancel => {
   
        cancelFun = cancel
    })
    stopRepeatRequest(config.url, cancelFun)
    return config;
}, error => {
   
    // Do something with request error
    return Promise.reject(error);
});
// 响应拦截
Ajax.interceptors.response.use(response => {
   
    // Do something before response is sent
    allowRequest()
    return response;
}, error => {
   
    // Do something with response error
    return Promise.reject(error);
});

const returnNewPro = (promise) => promise.then(res => {
   
    // console.log(promise.config.responseType, 'promisepromisepromise')
    if (promise.config && promise.config.responseType === 'arraybuffer') {
   
        return [null, res]
    }
    const resData = res.data;
    // context.$message.success('请求成功')
    return [null, resData]
}).catch(err => {
   
    console.log(err, 'promisepromisepromise')
    // code: "ERR_CANCELED"
    // message: "canceled"
    // name: "CanceledError"
    // stack: ""
    if (err.name === 'CanceledError') {
   
        console.log('多次请求接口------')
        // context.$message.info('让接口歇一会')
    } else {
   
        context.$message.error("接口请求失败");
    }
    return [err, null]
})

export const get = async (url, params, headers = {
   }) => {
   
    return await returnNewPro(Ajax.get(url, {
    params, headers }))
}
/**
 * 
 * @param {*} url 
 * @param {*} params 
 * @param {*} headers 
 * @returns [] 
 */
export const post = (url, params, headers = {
   }) => {
   
    return returnNewPro(Ajax.post(url, params, headers))
}

2023-10-20更新

/*
 * @Descripttion:
 * @version:
 * @Author: ZhangJunQing
 * @Date: 2022-05-23 11:46:01
 * @LastEditors: ZhangJunQing
 * @LastEditTime: 2022-08-30 14:41:25
 */
import axios from "axios";
import context from "@/main.js";
import {
    baseURL } from "@/Url";
import store from "@/store";
let reqList = [];
// 默认maxTime 节流操作目的是为了方式用户手滑点击多次新增或者修改
let maxTime = 100;
const Ajax = axios.create({
   
    // 是否携带cookie
    withCredentials: true,
    baseURL,
    timeout: 50000
});
// 过滤请求事件
const stopRepeatRequest = (url, cancelFun) => {
   
    // 过滤可以多次一直请求的接口
    // 情况包括整个页面调用了两次整个接口
    const filterList = [
        // 动态查询、展示列模板接口
        "/temp/query",
        // 获取省份地市接口
        "/sys/area/getCity",
        // 批量测速成功列表查询
        "/task/batch/listBatchResultByTaskId",
        // 地图json
        "/sys/gis/getGisJson"
    ];
    if (filterList.includes(url)) {
   
        return false;
    }
    // url存在  更新 time
    if (reqList.length !== 0 && reqList.find(i => i.url === url)) {
   
        // 存在
        // 存在 并且 还不能进行下次点击
        let arr = reqList.filter(
            item =>
                item.url === url && new Date().getTime() - item.time < maxTime
        );
        if (arr && arr.length !== 0) {
   
            cancelFun();
            return true;
        } else {
   
            // 存在能进行下一次点击  能进行接口连接
            reqList = reqList.map(i => {
   
                if (i.url === url) {
   
                    i.time = new Date().getTime();
                }
                return i;
            });
            return false;
        }
    } else {
   
        // 不存在直接添加 能进行接口连接
        reqList.push({
   
            url,
            time: new Date().getTime()
        });
        return false;
    }
};
// 接口请求完成后清除
const allowRequest = () => {
   
    if (reqList.length) {
   
        // 只保留不能多次请求的接口
        reqList = reqList.filter(
            item => new Date().getTime() - item.time < maxTime
        );
    }
};
// 请求拦截
Ajax.interceptors.request.use(
    config => {
   
        // 增加请求头
        config.headers["token"] = store.state.home.token;
        // config.headers["token"] = "666603941185868700"
        config.headers["authCode"] = store.state.home.authCode;
        // config.headers["authCode"] = "000001"
        config.headers["sysCode"] = store.state.home.sysCode;
        // config.headers["sysCode"] = "100015"
        let cancelFun = null;
        config.cancelToken = new axios.CancelToken(cancel => {
   
            cancelFun = cancel;
        });
        stopRepeatRequest(config.url, cancelFun);
        return config;
    },
    error => {
   
        // Do something with request error
        return Promise.reject(error);
    }
);
// 响应拦截
Ajax.interceptors.response.use(
    response => {
   
        // Do something before response is sent
        allowRequest();
        return response;
    },
    error => {
   
        // Do something with response error
        return Promise.reject(error);
    }
);

const returnNewPro = promise =>
    promise
        .then(res => {
   
            if (
                promise.config &&
                promise.config.responseType === "arraybuffer"
            ) {
   
                return [null, res];
            }
            const resData = res.data || res;
            if (resData.code && resData.code === 401) {
   
                setTimeout(() => {
   
                    process.env.VUE_APP_LOGOCLICK &&
                        window.open(process.env.VUE_APP_LOGOCLICK, "_self");
                },1000);
                return [null, resData];
            }
            // context.$message.success('请求成功')
            return [null, resData];
        })
        .catch(err => {
   
            // console.log(err, 'promisepromisepromise')
            // code: "ERR_CANCELED"
            // message: "canceled"
            // name: "CanceledError"
            // stack: ""
            if (err.name === "CanceledError") {
   
                // console.log('多次请求接口------')
                // context.$message.info('让接口歇一会')
            } else {
   
                if (err.response && err.response.status === 401) {
   
                    context.$message.error(err.response.data.message);
                    setTimeout(() => {
   
                        process.env.VUE_APP_LOGOCLICK &&
                            window.open(process.env.VUE_APP_LOGOCLICK, "_self");
                    },1000);
                } else if (err.response && err.response.status === 403) {
   
                    context.$message.error(err.response.data.message);
                } else {
   
                    // 防止多个接口都报错显示 接口请求失败
                    // 只有当前没有提醒的时候  才显示
                    if (
                        document.getElementsByClassName("el-message").length ==
                        0
                    ) {
   
                        //也就是当前没有提示弹窗
                        context.$message.error("接口请求失败");
                    }
                    // context.$message.closeAll();
                }
            }
            return [err, null];
        });
// 查询条件trim
export const get = async (url, params, headers = {
   }) => {
   
    if (params && JSON.stringify(params) !== "{}") {
   
        let newParams = {
   };
        for (const key in params) {
   
            if (Object.hasOwnProperty.call(params, key)) {
   
                const element = params[key];
                newParams[key] = String(element).trim();
            }
        }
        params = newParams;
    }
    return await returnNewPro(Ajax.get(url, {
    params, headers }));
};
/**
 *
 * @param {*} url
 * @param {*} params
 * @param {*} headers
 * @returns []
 */
export const post = (url, params, headers = {
   }) => {
   
    return returnNewPro(Ajax.post(url, params, headers));
};
目录
相关文章
|
资源调度 JavaScript
|
缓存 JavaScript 搜索推荐
|
前端开发 JavaScript Java
前端解决axios请求的跨域问题【2步完成】
本文介绍如何通过前端配置解决跨域问题,主要针对Vue项目中的`vite.config.js`文件进行修改。作者在联调过程中遇到跨域报错
803 1
|
JavaScript 前端开发 Java
SpringBoot项目的html页面使用axios进行get post请求
SpringBoot项目的html页面使用axios进行get post请求
260 2
|
Python
axios的get请求传入数组参数
【10月更文挑战第11天】 当使用 `axios` 发送包含数组参数的 GET 请求时,默认的序列化方式可能与后端(如 Django)不兼容,导致无法正确获取数组参数。解决方案是通过 `paramsSerializer` 指定自定义序列化函数,或使用 `qs` 库来格式化数组参数,确保前后端一致。示例代码展示了如何使用 `qs` 库设置 `arrayFormat` 为 `&quot;repeat&quot;`,以符合 Django 的解析要求。
614 2
|
JSON JavaScript 前端开发
axios的post请求,数据为什么要用qs处理?什么时候不用?
axios的post请求,数据为什么要用qs处理?什么时候不用?
|
JavaScript 前端开发 Java
SpringBoot项目的html页面使用axios进行get post请求
SpringBoot项目的html页面使用axios进行get post请求
251 7
|
JavaScript 前端开发 Java
SpringBoot项目的html页面使用axios进行get post请求
SpringBoot项目的html页面使用axios进行get post请求
214 0
|
前端开发 JavaScript UED
axios取消请求CancelToken的原理解析及用法示例
axios取消请求CancelToken的原理解析及用法示例
1154 0