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));
};
目录
相关文章
|
18天前
|
JavaScript 前端开发 开发者
vue中使用axios请求post接口,请求会发送两次
vue中使用axios请求post接口,请求会发送两次
|
1月前
|
Python
axios的get请求传入数组参数
axios的get请求传入数组参数
|
2天前
|
前端开发 JavaScript
React配合axios请求拦截校验session,403跳转至登陆页面
React中使用axios进行请求拦截,通过自定义事件监听和响应拦截实现403状态码时的自动登录页面跳转。
11 2
|
5天前
|
JSON 资源调度 JavaScript
Vue框架中Ajax请求的实现方式:使用axios库或fetch API
选择 `axios`还是 `fetch`取决于项目需求和个人偏好。`axios`提供了更丰富的API和更灵活的错误处理方式,适用于需要复杂请求配置的场景。而 `fetch`作为现代浏览器的原生API,使用起来更为简洁,但在旧浏览器兼容性和某些高级特性上可能略显不足。无论选择哪种方式,它们都能有效地在Vue应用中实现Ajax请求的功能。
14 4
|
3天前
|
JavaScript 前端开发
vue配合axios连接express搭建的node服务器接口_简单案例
文章介绍了如何使用Express框架搭建一个简单的Node服务器,并使用Vue结合Axios进行前端开发和接口调用,同时讨论了开发过程中遇到的跨域问题及其解决方案。
8 0
vue配合axios连接express搭建的node服务器接口_简单案例
|
1月前
|
移动开发 JavaScript 前端开发
"解锁axios GET请求新姿势!揭秘如何将数组参数华丽变身,让你的HTTP请求在云端翩翩起舞,挑战技术极限!"
【8月更文挑战第20天】二维码在移动应用中无处不在。本文详述了在UniApp H5项目中实现二维码生成与扫描的方法。通过对比插件`uni-app-qrcode`和库`qrcode-generator`生成二维码,以及使用插件和HTML5 API进行扫描,帮助开发者挑选最佳方案。无论是即插即用的插件还是灵活的JavaScript实现,都能满足不同需求。
28 0
|
2月前
|
存储 资源调度 前端开发
JavaScript 使用axios库发送 post请求给后端, 给定base64格式的字符串数据和一些其他参数, 使用表单方式提交, 并使用onUploadProgress显示进度
使用 Axios 发送包含 Base64 数据和其他参数的 POST 请求时,可以通过 `onUploadProgress` 监听上传进度。由于整个请求体被视为一个单元,所以进度可能不够精确,但可以模拟进度反馈。前端示例代码展示如何创建一个包含 Base64 图片数据和额外参数的 `FormData` 对象,并在上传时更新进度条。后端使用如 Express 和 Multer 可处理 Base64 数据。注意,实际进度可能不如文件上传精确,显示简单加载状态可能更合适。
|
2月前
|
NoSQL 前端开发 测试技术
若依修改,若依如何发送请求---王清江07,axios的请求在request.js文件中,若依发送GET请求,必须用param
若依修改,若依如何发送请求---王清江07,axios的请求在request.js文件中,若依发送GET请求,必须用param
|
1月前
|
JavaScript 前端开发
【Vue面试题二十五】、你了解axios的原理吗?有看过它的源码吗?
这篇文章主要讨论了axios的使用、原理以及源码分析。 文章中首先回顾了axios的基本用法,包括发送请求、请求拦截器和响应拦截器的使用,以及如何取消请求。接着,作者实现了一个简易版的axios,包括构造函数、请求方法、拦截器的实现等。最后,文章对axios的源码进行了分析,包括目录结构、核心文件axios.js的内容,以及axios实例化过程中的配置合并、拦截器的使用等。
【Vue面试题二十五】、你了解axios的原理吗?有看过它的源码吗?
|
1月前
|
JavaScript 前端开发
【Vue面试题二十七】、你了解axios的原理吗?有看过它的源码吗?
文章讨论了Vue项目目录结构的设计原则和实践,强调了项目结构清晰的重要性,提出了包括语义一致性、单一入口/出口、就近原则、公共文件的绝对路径引用等原则,并展示了单页面和多页面Vue项目的目录结构示例。