如何阻止重复请求
本文最后更新于
2019-10-28, 文中内容可能已过时,请注意甄别~
前端重复请求是一个很常见的问题,现有的解决方案有很多,如:
- 申明一个状态变量
- debounce 和 throttle
- axios 的 CancelToken
申明变量方式⌗
// 伪代码
let isShow = false // 初始状态
async handleFunc () {
isShow = true // isShow 为 true 时,按钮置灰等
await this.$apis.xxx()
isShow = false
}
// 这种方式的劣势是和业务代码耦合,每个请求都需要设置状态变量控制
debounce 和 throttle⌗
防抖和节流函数也是针对于频繁的事件触发,如 resize、input、scroll 等,具体操作可以看附录大佬的文章,今天主要看如何利用 axios 来全局阻止重复请求
axios 的 CancelToken⌗
在我们的项目中,一般都会对 axios 进行二次封装去使用,对请求、响应拦截器进行全局操作,如 HTTP 状态码、业务标识处理、全局 loading 以及我们今天说的阻止重复请求
axios 中是利用 CancelToken 来中止请求的,其实这就是原生 xhr.abort()
,具体逻辑如下:
import axios, { AxiosResponse, AxiosRequestConfig, AxiosError } from 'axios'
import router from '@/router'
import Vue from 'vue'
const flagMsg: string = 'FASTCLICK' // 连续点击错误标识
let pending: any[] = []
const cancelToken = axios.CancelToken // 初始化取消请求的构造函数
const removePending = (config: any, fn?: any) => {
const arr = config.url.split('/api') // 处理 baseURL
const flagUrl = arr[arr.length - 1]
if (pending.includes(flagUrl)) {
fn ? fn(flagMsg) : pending.splice(pending.indexOf(flagUrl), 1)
} else {
if (fn) {
pending.push(flagUrl)
}
}
}
// 创建 axios 实例
const instance = axios.create({
baseURL: '/api', // api 的 base_url
timeout: 60000, // 请求超时时间
})
/**
* request 拦截器
* @param config request拦截器
*/
const requestInterceptor = (config: AxiosRequestConfig) => {
config.cancelToken = new cancelToken(c => {
removePending(config, c)
})
return config
}
/**
* request 拦截器
* @param response 返回拦截器
*/
const responseInterceptor = (response: AxiosResponse<any>) => {
removePending(response.config)
const code = response.data.code
switch (code) {
case 'LOGIN_FAILED':
// 省略业务状态码
case 'TOKEN_EXPIRED': {
logOut() // 退出登录
setTimeout(() => {
router.push({ name: 'SignIn' })
}, 800)
}
default:
break
}
return response
}
/**
* 请求错误处理
* @param error error 实例
*/
const errorRequest = (error: AxiosError) => {
Vue.$handleError(error)
}
/**
* 响应错误处理
* @param error error 实例
*/
const errorResponse = (error: AxiosError) => {
pending = []
if (error.message === flagMsg) {
throw new Error('Jangan sering klik')
}
Vue.$handleError(error)
}
instance.interceptors.request.use(requestInterceptor, errorRequest)
instance.interceptors.response.use(responseInterceptor, errorResponse)
以上我们可以阻止点击造成的频繁请求,后续还可以加上全局 loading 或者 token 等,这个部分就不在这里写了,可以自己尝试一下
参考附录⌗
Read other posts