基于axios的请求封装
功能点
- 带有缓存功能
- 连续点击,能防止重复请求
- 能支持请求失败后的重试次数
- 声明式的调用方式
例子
import Axios from 'axios'
import { message } from 'ant-design-vue'
import { HttpRespData, RequestMethod } from './const'
import { getHttpBaseUrl, parseToken, getRequestIdentify } from './utils'
import router from '@/router'
import { handleHttp, getToken, getUid, getVueVersion } from '@/utils'
import { NoNeedTokenRequestMap } from '@/utils/models'
const instance = Axios.create({
timeout: 30000,
})
const CancelToken = Axios.CancelToken
const source = CancelToken.source()
// map用来保存所有正在请求的id
const requestMap = new Map()
export class Request {
public maxRetries = 1
private retries = 0
public headers = {}
public requestMethod = 'get'
public path = ''
public params = {}
private resolve = null as any
private reject = null as any
constructor() {
this.addAuthorizationHeader()
this.interceptorsResponse()
}
public send(): Promise<any> {
// const CancelToken = Axios.CancelToken
// const source = CancelToken.source()
// return handleHttp(
// instance[this.requestMethod as RequestMethod](this.path, this.params),
// )
return new Promise((resolve, reject) => {
if (!this.resolve && !this.reject) {
this.resolve = resolve
this.reject = reject
}
return handleHttp(
instance[this.requestMethod as RequestMethod](this.path, this.params, {
cancelToken: source.token,
}),
)
})
}
public method(method: string) {
this.requestMethod = method
return this
}
public setPath(path: string) {
this.path = path
return this
}
public setRetries(times: number) {
this.maxRetries = times
return this
}
public setHeaders(headers = {}) {
this.headers = { ...headers, ...this.headers }
return this
}
public setParams(params: any) {
this.params = params
return this
}
addAuthorizationHeader() {
let token = getToken() || ''
const uid = getUid() || ''
const vueVersion = getVueVersion() || '1'
if (!token || !uid) {
router
.replace({ name: 'login' })
.then(() => Promise.reject('认证失败, 请重新登录'))
}
token = parseToken(token)
this.headers = { Authorization: `${token};${vueVersion}`, uid }
}
static interceptorsRequest() {
instance.interceptors.request.use(
(config) => {
const requestData = getRequestIdentify(config)
// 取消重复请求
if (requestMap.has(requestData)) {
config.cancelToken = new CancelToken((c) => c('重复的请求被主动拦截'))
}
requestMap.set(requestData, true)
config.baseURL = getHttpBaseUrl()
if (NoNeedTokenRequestMap.get(config.url!)) {
return config
}
let token = getToken() || ''
const uid = getUid() || ''
const vueVersion = getVueVersion() || '1'
if (!token || !uid) {
router
.replace({ name: 'login' })
.then(() => Promise.reject('认证失败, 请重新登录'))
}
token = parseToken(token)
config.headers = {
...config.headers,
...{ Authorization: `${token};${vueVersion}`, uid },
}
return config
},
(error) => {
return Promise.reject(error)
},
)
}
interceptorsResponse() {
instance.interceptors.response.use(
(res) => {
const respData: HttpRespData = res.data
const requestData = getRequestIdentify(res.config)
requestMap.delete(requestData)
if (respData.result === 0) {
this.resolve(respData.data)
return respData.data
}
// 请求失败次数加一
this.retries += 1
// 请求失败的次数小于maxRetries,则再次发送请求
if (this.retries < this.maxRetries) return this.send()
this.retries = 0
// handle error
const errData: string = respData.data
const errMsg: string = errData
if (errMsg) {
message.error(errMsg)
}
return this.reject(respData)
},
(error) => {
console.log(error)
if (error.response) return Promise.reject(error.response.data)
return Promise.reject(error.message)
},
)
}
}
Request.interceptorsRequest()
使用方式
(new Request()).method('get').path('/login').setHeaders({content-type" 'asdad'}).setRetries(8).setParams({password: '1111',username: 'xxxx'}).send()
注意:现在新版本的axios使用AbortController取消请求,示例如下
const controllMap = new Map();
const commonRequest = (key, url, data) => {
if (controllMap.has(key)) {
controllMap.get(key).abort();
}
const controll = new AbortControll();
controllMap.set(key, controll)
return axios.post(url, {
...data,
signal: controll.signal,
})
}