记录-axios配置可控取消重复请求

143 阅读2分钟

背景:

其实我感觉没什么用,影响不会很大,但是还是那句话:你可以没有,但不可以不会~ 程序员还是得有所追求,严谨🧐

使用场景:

发生重复请求的场景一般有这些:

  • 快速连续点击一个按钮,如果你没有做禁用处理,那么弱网情况下就可以不断点击触发请求。
  • 对于列表数据,可能有tab状态栏的频繁切换查询,如果请求响应很慢,也会产生重复请求。当然现在很多列表都会做缓存,如Vue中用 <keep-alive />

方法

ajax用.abort()中断一个已被发出的请求,我们主要讲axios,用的是CancelToken,这是文档

思路

  • 定义pending数组,收集请求信息。
  • 用axios生成cancel函数和cancelToken。
  • 每次axios请求之前判断pending中是否有该请求信息,如果有,则利用axios生成的cancel函数和 cancelToken取消之前请求,再把本次请求信息添加pending。如果没有,则直接添加。
  • 接口返回后,移除pending数组中该请求信息。

直接上代码

// utils/request.js

import axios from 'axios'
imort { Message }  from 'element-ui'
imiport router from '../router'
imort Qs from 'qs'

function myAxios(axiosConfig, customOptions) {
    const service = axios.create({
        // baseURL: 'XXX'
        timeout: 6000, // request timeout
        withCredentials: true // 允许为自己域设置cookie
    })
    
    // 自定义配置
    let custom_options = Object.assign({
        repeat_request_cancel: false, // 是否开启取消重启请求,默认为true
    }, customOptions)
    
    // request interceptor
    service.interceptors.request.use(
        config => {
            config.headers.Authorization = 'Bearer ' + localStorage.token //JWT认证
            custom_options.repeat_request_cancel && addPendingRequest(config) // 把当前请求信息添加到pendingRequest对象中
            return config
        },
        err => {
            // 返回带有拒绝原因的Promise对象
            return Promise.reject(err)
        }
    )
    
    // response interceptor
    service.interceptors.response.use(
        response => {
            removePendingRequest(response.config) // 从pendingRequest对象中移除请求
            const { data, status } = response
            // do some thing
        },
        err => {
            removePendingRequest(err.config || {}) // 从pendingRequest对象中移除请求
            if (axios.isCancel(err)) {
                console.log('已取消重复请求' + err.message)
            }
            return Promise.reject(err)
        }
    )
    return service(axiosConfig)
}


// 用于根据当前请求的信息,生成请求Key
function generateReqKey (config) {
    const { method, url, params, data } = config
    return [method, url, Qs.stringify(params), Qs.stringify(data)].join('&')
}

// 用于把当前请求信息添加到pendingRequest对象中
const pendingRequest = new Map()
function addPendingRequest (config) {
    const requestKey = generateReqKey(config)
    config.cancelToken = config.cancelToken || new axios.CancelToken((cancel) => {
        if(!pendingRequest.has(requestKey)) {
            pendingRequest.set(sequestKey, cancel)
        }
    })
}

// 检查是否有存在重复请求,若存在则取消已发请求
function removePendingRequest (config) {
    const requestKey = generateReqKey(config)
    if (pendingRequest.has(requestKey)) {
        const cancelToken = pendingRequest.get(requestKey)
        cancelToken(requestKey)
        pendingRequest.delete(requestKey)
    }
}

export default myAxios

// home.vue import axios from '../utils/request'

axios({
    method: 'post',
    url: 'xxx',
    params: {xxx}
}, {
    repeat_request_cancel: false
})
    .then(res => xxx)
    .catch(err => xxx)
  

结尾

有收获希望能一键三连😁谢谢~