import axios from "axios";
const request = axios.create({
baseURL:'http://localhost:3000',
timeout:6000
})
// 发布订阅
class EventEmitter {
constructor(){
this.event = {} // 定义event对象的数据
}
// 往event对象中添加数据的方法
on(type,cbres,cbrej){
// 如果对象中不存在这个属性 便添加这个属性
if(!this.event[type]){
this.event[type] = [[cbres,cbrej]]
}else{
// 如果对象中存在这个属性就继续往这个对象中进行添加
this.event[type].push([cbres,cbrej])
}
}
emit(type,res,ansType){
// 如果event中对象的属性不存在就停止执行后面的代码
if(!this.event[type]){
return false
}else{
// 如果存在 就将这个数据中对应的属性的值进行遍历,该对象属性值是一个数组,并且是一个数组包含数组的模式
this.event[type].forEach(cbArr=>{
if(ansType==='resolve'){
cbArr[0](res)
}else{
cbArr[1](res)
}
})
}
}
}
// 根据请求生成对应的key
function generateReqkey(config,hash){
const {method,url,params,data} = config
return [method,url,JSON.stringify(params),JSON.stringify(data),hash].join('&')
}
// 存储已发送但未响应的请求
const pendingRequest = new Set()
// 发布订阅的容器
const ev = new EventEmitter()
// 请求拦截器
request.interceptors.request.use(async(config)=>{
console.log(location)
// 获取hash
let hash = location.hash
console.log('hahs',hash)
// 生成请求的key
let reqKey = generateReqkey(config,hash)
console.log('key',reqKey)
if(pendingRequest.has(reqKey)){
// 如果已经存在相同的请求,在这里将请求挂起 通过发布订阅来为该请求返回结果
// 这里需注意拿到结果后 无论成功是否 都需要return promise.reject()中断请求 否则请求将会正常发送服务器
let res = null
try{
// 接口成功响应
res = await new Promise((resolve,reject)=>{
ev.on(reqKey,resolve,reject)
})
console.log(res)
return Promise.reject({
type:'limiteResSuccess',
val:res
})
}catch(limitFunErr){
// 接口报错
return Promise.reject({
type:'limiteResError',
val:limitFunErr
})
}
}else{
config.pendKey = reqKey
console.log('config',config)
pendingRequest.add(reqKey)
console.log(pendingRequest)
}
return config
},function(error){
return Promise.reject(error)
})
// 添加响应拦截器
request.interceptors.response.use(function(response){
console.log(response)
// 将拿到的结果发布给其他相同的接口
handleSuccessResponse_limit(response)
return response
},function(error){
return handleErrorResponse_limit(error)
})
// 接口响应成功
const handleSuccessResponse_limit = (response)=>{
console.log(response)
const reqKey = response.config.pendKey
if(pendingRequest.has(reqKey)){
console.log('存在吗')
let x = null
try{
x = JSON.parse(JSON.stringify(response))
console.log(x)
}catch(e){
x = response
}
pendingRequest.delete(reqKey)
console.log(pendingRequest)
ev.emit(reqKey,x,'resolve')
delete ev.reqKey
}
}
// 接口走失败的响应
function handleErrorResponse_limit(error){
if(error.type&&error.type==='limiteResSuccess'){
return Promise.resolve(error.val)
}else if(error.type&&error.type==='limiteResError'){
return Promise.reject(error.val)
}else{
const reqKey = error.config.pendKey
if(pendingRequest.has(reqKey)){
let x = null
try{
x = JSON.parse(JSON.stringify(error))
}catch(e){
x = error
}
pendingRequest.delete(reqKey)
ev.emit(reqKey,x,'reject')
delete ev.reqKey
}
}
return Promise.reject(error)
}
export default request
防止重复点击,在服务端未响应之前,多次请求数据
最新推荐文章于 2024-07-17 15:26:15 发布
文章描述了一个使用axios库构建的HTTP请求管理模块,包括请求拦截器、响应拦截器以及基于发布订阅模式的请求限流与结果处理。它通过生成请求key跟踪未响应的请求,并在相同请求重复时利用事件机制返回之前的结果。
摘要由CSDN通过智能技术生成