文档管理
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

235 lines
6.8 KiB

import type {
AxiosInstance,
AxiosRequestConfig,
AxiosRequestHeaders,
AxiosResponse,
InternalAxiosRequestConfig,
} from 'axios'
import qs from 'qs'
import Keys from '../Keys'
import { useMessage } from '@/hooks/useMessage'
import axios, { AxiosError, isCancel } from 'axios'
import {
getRefreshToken,
getTenantId,
getToken,
removeToken,
setToken,
} from '@/utils/auth'
import { authErrMap, ignoreMsgs, networkErrMap } from '../basic/utils'
import type { Result } from '../basic/httpTypes'
import type { APIConfigKeys } from './config'
import { openSocket, closeSocket } from '@/pages/socket_server/index'
import { RouterView, useRouter } from 'vue-router'
import { deleteUserCache } from '@/hooks/useCache'
const router = useRouter()
const VITE_BASE_API_SYSTEM = import.meta.env.VITE_BASE_API_SYSTEM
const message = useMessage()
const basicHeader = {
tenant() {
const tenant = getTenantId()
if (tenant) return tenant
return ''
},
token() {
const token = getToken()
if (token) return 'Bearer ' + token
return ''
},
testToken: 'Bearer test',
}
interface Config {
baseURL?: string
baseAPI: string
}
const instances: Record<string, AxiosInstance> = {}
let isRefreshToken = false // 是否正在刷新中
let requestList: any[] = [] // 请求队列
const createAxiosInstance = (module: APIConfigKeys, config: Config) => {
if (!config || !config.baseAPI) {
throw new Error(`Invalid configuration for module: ${module}`)
}
const { baseAPI } = config
if (!instances[module]) {
const instance = axios.create({
baseURL: `${baseAPI}`,
timeout: 10000,
headers: {
'Content-Type': 'application/json',
},
})
instances[module] = instance
}
const service = instances[module]
service.interceptors.request.use(
(config: InternalAxiosRequestConfig): InternalAxiosRequestConfig => {
config.headers.Authorization = basicHeader.token()
// config.headers['tenant-id'] = basicHeader.tenant()
const params = config.params || {}
const data = config.data || false
if (
config.method?.toUpperCase() === 'POST' &&
(config.headers as AxiosRequestHeaders)['Content-Type'] ===
'application/x-www-form-urlencoded'
) {
config.data = qs.stringify(data)
}
if (config.method?.toUpperCase() === 'GET' && params) {
config.params = {}
const paramsStr = qs.stringify(params, { allowDots: true })
if (paramsStr) {
config.url = config.url + '?' + paramsStr
}
}
return config
},
(error: AxiosError): Promise<AxiosError> => {
return Promise.reject(error)
}
)
service.interceptors.response.use(
async (res: AxiosResponse) => {
const config = res.config
let { data } = res
if (!res.data) {
throw new Error('返回“[HTTP]请求没有返回值”')
}
if (
res.request.responseType === 'blob' ||
res.request.responseType === 'arraybuffer'
) {
// 注意:如果导出的响应为 json,说明可能失败了,不直接返回进行下载
if (res.data.type !== 'application/json') {
return Promise.resolve({ code: res.status, data: res.data })
}
data = await new Response(res.data).json()
}
const code = data.code || 200
const msg = data.msg || authErrMap[code] || authErrMap['default']
if (ignoreMsgs.indexOf(msg) !== -1) {
// 如果是忽略的错误码,直接返回 msg 异常
return Promise.reject({ code: null, msg })
} else if (code === 401) {
if (!isRefreshToken) {
isRefreshToken = true
// if (!getRefreshToken()) logout()
try {
const refreshTokenRes = await refreshToken()
if (refreshTokenRes.data.code !== 0) {
// logout()
return Promise.reject({ code, msg })
}
setToken(refreshTokenRes.data.data.accessToken)
config.headers!.Authorization = 'Bearer ' + getToken()
requestList.forEach((cb: any) => {
cb()
})
requestList = []
// 重连接socket
// openSocket()
return service(config)
} catch (e) {
// logout()
return Promise.reject({ code, msg })
} finally {
requestList = []
isRefreshToken = false
}
} else {
return new Promise(resolve => {
requestList.push(() => {
config.headers!.Authorization = 'Bearer ' + getToken()
resolve(service(config))
})
})
}
} else if (code === 500) {
return Promise.reject({ code, msg })
} else if (code !== 200) {
// if (msg === '无效的刷新令牌') {
// // hard coding:忽略这个提示,直接登出
// console.log(msg)
// } else {
// ElMessage.error(msg)
// }
return Promise.reject({ code, msg })
}
return data
},
(error: any): Promise<any> => {
if (isCancel(error)) {
return Promise.resolve()
}
const message = '请求错误'
if (error.code === 'ECONNABORTED') {
return Promise.reject({ code: null, msg: '服务器响应超时' })
}
if (!error.response) {
return Promise.reject({ code: null, msg: message })
}
const status = error.response?.status
const unKnowError = `连接出错(${error.response.status})!`
if (status === 401) {
localStorage.removeItem(Keys.STORAGE_TOKEN)
router.push('/file/document')
}
const msg = networkErrMap[status] ? networkErrMap[status] : unKnowError
return Promise.reject({ code: status || null, msg: msg })
}
)
if (!service) {
throw new Error(`Failed to create Axios instance for module: ${module}`)
}
const refreshToken = async () => {
// axios.defaults.headers.common['tenant-id'] = getTenantId()
return await axios.post(
`${VITE_BASE_API_SYSTEM}/auth/refresh-token?refreshToken=` + getRefreshToken()
)
}
async function request<T = any>(config: AxiosRequestConfig): Promise<Result<T>> {
try {
const result = (await service(config)) as Result<T>
return result
} catch (err: any) {
const result: Result<T> = {
code: err?.code || -1,
msg: err.msg || err.message,
data: err.data || null,
}
return result
}
}
return request
}
let isShowLogout = false
async function logout() {
if (isShowLogout) return
isShowLogout = true
await message.forceConfirm('登录状态已失效,请重新登录', '系统提示', '重新登录')
removeToken()
isShowLogout = false
deleteUserCache()
window.location.href = '/file/document'
}
export default createAxiosInstance