Files
Web_BAI_Manage_ApiServer/front-end/src/utils/request.ts
XuJiacheng 9a387f3eec feat: 初始化项目结构并添加基础配置
添加前后端基础项目结构,包括.gitignore、package.json等配置文件
实现前端基础功能模块,包括路由、状态管理、API请求封装等
添加前端UI组件库和样式体系
配置开发环境Mock系统和构建工具链
2026-03-18 14:03:35 +08:00

197 lines
6.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import qs from 'qs'
import { addErrorLog, needErrorLog } from '@vab/plugins/errorLog'
import { gp } from '@gp'
import { useUserStore } from '@/store/modules/user'
import {
baseURL,
contentType,
debounce,
messageName,
requestTimeout,
statusName,
successCode,
} from '@/config'
import router from '@/router'
import { isArray } from '@/utils/validate'
import { refreshToken } from '@/api/refreshToken'
let loadingInstance: any
let refreshToking = false
let requests: (() => void)[] = []
// 操作正常Code数组
const codeVerificationArray = isArray(successCode)
? [...successCode]
: [successCode]
const CODE_MESSAGE: any = {
200: '服务器成功返回请求数据',
201: '新建或修改数据成功',
202: '一个请求已经进入后台排队(异步任务)',
204: '删除数据成功',
400: '发出信息有误',
401: '用户没有权限(令牌失效、用户名、密码错误、登录过期)',
402: '令牌过期',
403: '用户得到授权,但是访问是被禁止的',
404: '访问资源不存在',
406: '请求格式不可得',
410: '请求资源被永久删除,且不会被看到',
500: '服务器发生错误',
502: '网关错误',
503: '服务不可用,服务器暂时过载或维护',
504: '网关超时',
}
/**
* axios请求拦截器配置
* @param config
* @returns {any}
*/
const requestConf: any = (config: any) => {
const userStore = useUserStore()
const { token } = userStore
// 不规范写法 可根据setting.config.js tokenName配置随意自定义headers
// if (token) config.headers[tokenName] = token
// 规范写法 不可随意自定义
if (token) config.headers['Authorization'] = `Bearer ${token}`
if (
config.data &&
config.headers['Content-Type'] ===
'application/x-www-form-urlencoded;charset=UTF-8'
)
config.data = qs.stringify(config.data)
if (debounce.some((item) => config.url.includes(item)))
loadingInstance = gp.$baseLoading()
return config
}
/**
* 刷新刷新令牌
* @param config 过期请求配置
* @returns {any} 返回结果
*/
const tryRefreshToken = async (config: any) => {
if (!refreshToking) {
refreshToking = true
try {
const {
data: { token },
}: any = await refreshToken()
if (token) {
const { setToken } = useUserStore()
setToken(token)
// 已经刷新了token将所有队列中的请求进行重试
requests.forEach((cb: any) => cb(token))
requests = []
return instance(requestConf(config))
}
} catch (error) {
console.error('refreshToken error =>', error)
router.push({ path: '/login', replace: true }).then(() => {})
} finally {
refreshToking = false
}
} else {
return new Promise((resolve) => {
// 将resolve放进队列用一个函数形式来保存等token刷新后直接执行
requests.push(() => {
resolve(instance(requestConf(config)))
})
})
}
}
/**
* axios响应拦截器
* @param config 请求配置
* @param data response数据
* @param status HTTP status
* @param statusText HTTP status text
* @returns {Promise<*|*>}
*/
const handleData = async ({ config, data, status, statusText }: any) => {
const { resetAll } = useUserStore()
if (loadingInstance) loadingInstance.close()
// 若data.code存在覆盖默认code
let code = data && data[statusName] ? data[statusName] : status
// 若code属于操作正常code则status修改为200
if (codeVerificationArray.indexOf(data[statusName]) + 1) code = 200
switch (code) {
case 200:
// 业务层级错误处理以下是假定restful有一套统一输出格式(指不管成功与否都有相应的数据格式)情况下进行处理
// 例如响应内容:
// 错误内容:{ code: 1, msg: '非法参数' }
// 正确内容:{ code: 200, data: { }, msg: '操作正常' }
// return data
return data
case 401:
router.push({ path: '/login', replace: true }).then(() => {
resetAll().then(() => {})
})
break
case 402:
return await tryRefreshToken(config)
case 403:
router.push({ path: '/403' }).then(() => {})
break
}
// 异常处理
// 若data.msg存在覆盖默认提醒消息
const errMsg = `${
data && data[messageName]
? data[messageName]
: CODE_MESSAGE[code]
? CODE_MESSAGE[code]
: statusText
}`
// 是否显示高亮错误(与errorHandler钩子触发逻辑一致)
gp.$baseMessage(errMsg, 'error', 'vab-hey-message-error', false)
if (needErrorLog())
addErrorLog({ message: errMsg, stack: data, isRequest: true })
throw data
}
/**
* @description axios初始化
*/
const instance = axios.create({
baseURL,
timeout: requestTimeout,
headers: {
'Content-Type': contentType,
},
})
/**
* @description axios请求拦截器
*/
instance.interceptors.request.use(requestConf, (error) => {
return Promise.reject(error)
})
/**
* @description axios响应拦截器
*/
instance.interceptors.response.use(
(response) => handleData(response),
(error) => {
const { response } = error
if (response === undefined) {
if (loadingInstance) loadingInstance.close()
gp.$baseMessage(
'连接后台接口失败可能由以下原因造成后端不支持跨域CORS、接口地址不存在、请求超时等请联系管理员排查后端接口问题 ',
'error',
'vab-hey-message-error',
false
)
return {}
} else return handleData(response)
}
)
export default instance