import { useUserStore } from "@/store"
|
import { getToken } from "@/utils/auth"
|
import storage from "@/utils/storage"
|
import { showMessage } from "./status"
|
|
// 重试队列,每一项将是一个待执行的函数形式
|
let requestQueue = []
|
|
// 防止重复提交
|
const repeatSubmit = config => {
|
const requestObj = {
|
url: config.url,
|
data:
|
typeof config.data === "object"
|
? JSON.stringify(config.data)
|
: config.data,
|
time: new Date().getTime()
|
}
|
const sessionObj = storage.getJSON("sessionObj")
|
if (!sessionObj) {
|
storage.setJSON("sessionObj", requestObj)
|
} else {
|
const s_url = sessionObj.url // 请求地址
|
const s_data = sessionObj.data // 请求数据
|
const s_time = sessionObj.time // 请求时间
|
const interval = 1000 // 间隔时间(ms),小于此时间视为重复提交
|
if (
|
s_data === requestObj.data &&
|
requestObj.time - s_time < interval &&
|
s_url === requestObj.url
|
) {
|
const message = "数据正在处理,请勿重复提交"
|
console.warn(`[${s_url}]: ${message}`)
|
return Promise.reject(new Error(message))
|
} else {
|
storage.setJSON("sessionObj", requestObj)
|
}
|
}
|
}
|
|
// 是否正在刷新token的标记
|
let isRefreshing = false
|
|
// 刷新token
|
const refreshToken = async (http, config) => {
|
// 是否在获取token中,防止重复获取
|
if (!isRefreshing) {
|
// 修改登录状态为true
|
isRefreshing = true
|
// 等待登录完成
|
await useUserStore().authLogin()
|
// 登录完成之后,开始执行队列请求
|
requestQueue.forEach(cb => cb())
|
// 重试完了清空这个队列
|
requestQueue = []
|
isRefreshing = false
|
// 重新执行本次请求
|
return http.request(config)
|
}
|
|
return new Promise(resolve => {
|
// 将resolve放进队列,用一个函数形式来保存,等登录后直接执行
|
requestQueue.push(() => {
|
resolve(http.request(config))
|
})
|
})
|
}
|
|
function requestInterceptors(http) {
|
/**
|
* 请求拦截
|
* @param {object} http
|
*/
|
http.interceptors.request.use(
|
config => {
|
// 可使用async await 做异步操作
|
// 初始化请求拦截器时,会执行此方法,此时data为undefined,赋予默认{}
|
config.data = config.data || {}
|
// 自定义参数
|
const custom = config?.custom
|
|
// 是否需要设置 token
|
const isToken = custom?.auth === false
|
if (getToken() && !isToken && config.header) {
|
// token设置
|
config.header.token = getToken()
|
}
|
|
// 是否显示 loading
|
if (custom?.loading) {
|
uni.showLoading({
|
title: "加载中",
|
mask: true
|
})
|
}
|
|
// 是否需要防止数据重复提交
|
const isRepeatSubmit = custom?.repeatSubmit === false
|
if (
|
!isRepeatSubmit &&
|
(config.method === "POST" || config.method === "UPLOAD")
|
) {
|
repeatSubmit(config)
|
}
|
return config
|
},
|
(
|
config // 可使用async await 做异步操作
|
) => Promise.reject(config)
|
)
|
}
|
function responseInterceptors(http) {
|
/**
|
* 响应拦截
|
* @param {object} http
|
*/
|
http.interceptors.response.use(
|
response => {
|
/* 对响应成功做点什么 可使用async await 做异步操作 */
|
const data = response.data
|
// 配置参数
|
const config = response.config
|
// 自定义参数
|
const custom = config?.custom
|
|
// 登录状态失效,重新登录
|
if (data.code === 401) {
|
return refreshToken(http, config)
|
}
|
|
// 隐藏loading
|
if (custom?.loading) {
|
uni.hideLoading()
|
}
|
|
// 请求成功则返回结果
|
if (data.code === 200) {
|
return response || {}
|
}
|
|
// 如果没有显式定义custom的toast参数为false的话,默认对报错进行toast弹出提示
|
if (custom?.toast !== false) {
|
uni.$u.toast(data.message)
|
}
|
|
// 请求失败则抛出错误
|
return Promise.reject(data)
|
},
|
response => {
|
// 自定义参数
|
const custom = response.config?.custom
|
|
// 隐藏loading
|
if (custom?.loading !== false) {
|
uni.hideLoading()
|
}
|
|
// 如果没有显式定义custom的toast参数为false的话,默认对报错进行toast弹出提示
|
if (custom?.toast !== false) {
|
const message = response.statusCode
|
? showMessage(response.statusCode)
|
: "网络连接异常,请稍后再试!"
|
uni.$u.toast(message)
|
}
|
|
return Promise.reject(response)
|
}
|
)
|
}
|
|
export { requestInterceptors, responseInterceptors }
|