import axios from 'axios'
import { Toast } from 'vant'
import store from '@/store'
import qs from 'qs'
let userInfo:string = (<any>window).localStorage.getItem('vuex')
let parseToken = userInfo ? JSON.parse(userInfo).me?.info?.clientToken :''
const token:string = (<any>store) ? (<any>store).state.me.info.clientToken : parseToken
const pendingRequest = new Map() // 请求对象
const CancelToken = axios.CancelToken
const service = axios.create({
baseURL: process.env.NODE_ENV === 'production' ? '' : process.env.VUE_APP_BASE_API,
timeout: 60000,
headers: {
'Content-Type': 'application/json;charset=UTF-8',
'x-chat-terminal': 'Client',
'x-chat-machine': 'Client',
'x-chat-version': '1.0.0',
}
})
service.interceptors.request.use(
config => {
if (token) {
if (!config.headers.customize) {
config.headers = {
'x-chat-token': token,
...config.headers
}
} else {
config.headers = {
'x-chat-token': token,
'Content-Type': 'application/json',
}
}
}
let requestKey = getReqKey(config)
// 判断是否是重复请求
if (pendingRequest.has(requestKey)) { // 是重复请求
removeReqKey(requestKey); // 取消
} else {
// 设置cancelToken
config.cancelToken = new CancelToken(function executor(cancel) {
pendingRequest.set(requestKey, cancel) // 设置
})
}
return config
}, error => {
Promise.reject(error)
}
)
service.interceptors.response.use(
response => {
let requestKey = getReqKey(response.config);
removeReqKey(requestKey)
const res = response.data
// 这里可以判断登录状态 ……
if (response.status === 200 && res.code === 0) {
return res
} else {
if (res.code != '-95' && res.code !== -145){
Toast(res?.msg || '服务器错误')
}
return Promise.reject(res)
}
},
error => {
let status:number = 200
try {
status = error.response.status
} catch (e) {
if (error.toString().indexOf('Error: timeout') !== -1) {
Toast( '网络请求超时')
return Promise.reject(error)
}
if (error.toString().indexOf('Error: Network Error') !== -1) {
Toast( '网络请求错误')
return Promise.reject(error)
}
if (status === 401) {
Toast( '登录状态已过期')
return Promise.reject(error)
}
}
const statusMap = new Map([
[400, '参数错误'],
[401, '需要身份认证'],
[403, '拒绝访问'],
[404, '请求错误,未找到该资源'],
[405, '请求方法被禁止'],
[406, '请求无法完成'],
[407, '代理请求需要授权'],
[408, '服务器等待客户端发送的请求时间过长'],
[409, '服务器处理请求时发生了冲突'],
[410, '请求资源被永久删除了'],
[413, '请求数据太大'],
[414, '请求url过长'],
[415, '服务器无法处理请求附带的媒体格式'],
[500, '服务器端出错!'],
[501, '不支持的请求'],
[502, '线路繁忙'],
[503, '系统升级维护中'],
[504, '请求超时!请尝试刷新页面重试']
])
if(statusMap.get(status)) {
Toast(statusMap.get(status))
}
let requestKey = getReqKey(error.config)
removeReqKey(requestKey)
return Promise.reject(error)
}
)
export default service
// 获取请求key
function getReqKey(config:any) {
console.log('config:',config)
// 请求方式、请求地址、请求参数生成的字符串来作为是否重复请求的依据
const { method, url, params = {}, data } = config // 解构出来这些参数
// GET ---> params POST ---> data
const requestKey = [ method, url, qs.stringify(params), qs.stringify(data)].join('&')
console.log('requestKey:',requestKey)
return requestKey
}
// 取消重复请求
function removeReqKey(key:string) {
if( pendingRequest.has(key) ) {
const cancelToken = pendingRequest.get(key)
cancelToken(key) // 取消之前发送的请求
pendingRequest.delete(key) // 请求对象中删除requestKey
}
}
import axios from 'axios'
const cloneDeep = require('clone-deep')
const instance = axios.create()
//定义缓存对象
//因为需要频繁读写数据,所以这里使用性能更高的map对象
const cacheMap = new Map()
//手动刷新刷新缓存
export function clearCache() {
cache.clear()
}
//生成请求标识
function generateRequestKey(config, isRes = false) {
let requestKey = config.url
// 响应返回的请求配置中的data是字符串,请求发送的请求配置中的data是对象
if (isRes) {
requestKey += (config.data ?? '') + (JSON.stringify(config.params) ?? '')
} else {
requestKey +=
(JSON.stringify(config.data) ?? '') +
(JSON.stringify(config.params) ?? '')
}
return requestKey
}
//缓存时效
const cacheExpirationTime = 1000 * 60 * 60 //1小时更新一次
//请求拦截
instance.interceptors.request.use(
config => {
//获取当前请求的请求标识
const key = generateRequestKey(config)
//读取请求缓存
const requestCache = cacheMap.get(key)
//缓存存在并且缓存并未过期,返回缓存,否则正常发送请求
if (
requestCache &&
new Date() - requestCache.cacheDate < cacheExpirationTime
) {
return Promise.reject({
cached: true,
key
})
}
//如果当前请求未被缓存,则正常发送请求
return config
},
error => {
// 对请求错误做些什么
return Promise.reject(error)
}
)
//响应拦截
instance.interceptors.response.use(
res => {
if (res.data.code === '00') {
const key = generateRequestKey(res.config, true)
if (!cacheMap.has(key)) {
cacheMap.set(key, { cacheDate: new Date(), res: cloneDeep(res.data) })
} else {
// 若已存在缓存,并且缓存已过期,则更新缓存
const requestCache = cacheMap.get(key)
if (new Date() - requestCache.cacheDate > cacheExpirationTime) {
cacheMap.set(key, {
cacheDate: new Date(),
res: cloneDeep(res.data)
})
}
}
}
return res.data
},
err => {
if (err.cached) {
//返回缓存
return Promise.resolve(cloneDeep(cacheMap.get(err.key)))
} else {
// 对响应错误做点什么
return Promise.reject(err)
}
}
)
export default instance