forked from natuka/web.puabadge.com
137 lines
3.8 KiB
TypeScript
137 lines
3.8 KiB
TypeScript
import type { AxiosError, InternalAxiosRequestConfig } from 'axios'
|
||
import axios from 'axios'
|
||
import { showNotify } from 'vant'
|
||
import { localStorage } from '@/utils/local-storage'
|
||
import { STORAGE_TOKEN_KEY } from '@/stores/mutation-type'
|
||
|
||
// 这里是用于设定请求后端时,所用的 Token KEY
|
||
// 可以根据自己的需要修改,常见的如 Access-Token,Authorization
|
||
// 需要注意的是,请尽量保证使用中横线`-` 来作为分隔符,
|
||
// 避免被 nginx 等负载均衡器丢弃了自定义的请求头
|
||
export const REQUEST_TOKEN_KEY = 'Authorization'
|
||
|
||
// 创建 axios 实例
|
||
const request = axios.create({
|
||
// API 请求的默认前缀
|
||
baseURL: process.env.VUE_APP_API_BASE_URL,
|
||
// 上传/生图等接口常超过 6s;过短会导致旧业务也误超时
|
||
timeout: 30000,
|
||
})
|
||
|
||
export type RequestError = AxiosError<{
|
||
message?: string
|
||
result?: any
|
||
errorMessage?: string
|
||
}>
|
||
|
||
// 异常拦截处理器
|
||
const errorHandler = (error: RequestError): Promise<any> => {
|
||
if (error.response) {
|
||
const { data = {}, status, statusText } = error.response
|
||
// 403 无权限
|
||
if (status === 403) {
|
||
showNotify({
|
||
type: 'danger',
|
||
message: (data && data.message) || statusText,
|
||
})
|
||
}
|
||
// 401 未登录/未授权
|
||
if (status === 401) {
|
||
showNotify({
|
||
type: 'danger',
|
||
message: (data && data.message) || '链接已失效,请联系平台客服',
|
||
duration: 0
|
||
})
|
||
// 如果你需要直接跳转登录页面
|
||
// location.replace(loginRoutePath)
|
||
}
|
||
}
|
||
return Promise.reject(error)
|
||
}
|
||
|
||
// 请求拦截器
|
||
const requestHandler = (config: InternalAxiosRequestConfig): InternalAxiosRequestConfig | Promise<InternalAxiosRequestConfig> => {
|
||
// 从 localStorage 读取 code(刷新时也能获取到)
|
||
const code = localStorage.get('code')
|
||
const userId = localStorage.get('userId')
|
||
|
||
// 让每个请求携带自定义 token, 请根据实际情况修改
|
||
if (code) {
|
||
config.headers['Authorization'] = code
|
||
}
|
||
if (userId) {
|
||
config.headers['Userid'] = userId
|
||
}
|
||
|
||
return config
|
||
}
|
||
|
||
// Add a request interceptor
|
||
request.interceptors.request.use(requestHandler, errorHandler)
|
||
|
||
function coerceJsonPayload(payload: any) {
|
||
// 后端若用 text/plain 返回 JSON,axios 不会自动 parse,这里补一层
|
||
if (typeof payload !== 'string') return payload
|
||
const text = payload.replace(/^\uFEFF/, '').trim()
|
||
if (!text) return payload
|
||
try {
|
||
return JSON.parse(text)
|
||
} catch {
|
||
const start = text.indexOf('{')
|
||
const end = text.lastIndexOf('}')
|
||
if (start >= 0 && end > start) {
|
||
try {
|
||
return JSON.parse(text.slice(start, end + 1))
|
||
} catch {
|
||
return payload
|
||
}
|
||
}
|
||
return payload
|
||
}
|
||
}
|
||
|
||
// 响应拦截器
|
||
const responseHandler = (response: { data: any }) => {
|
||
if (!response?.data && response?.data !== 0 && response?.data !== false)
|
||
return response
|
||
|
||
// 兼容偶发双层:{ data: { code, data, message } }
|
||
let payload = coerceJsonPayload(response.data)
|
||
if (
|
||
payload &&
|
||
typeof payload === 'object' &&
|
||
payload.code == null &&
|
||
payload.data &&
|
||
typeof payload.data === 'object' &&
|
||
payload.data.code != null
|
||
) {
|
||
payload = payload.data
|
||
}
|
||
|
||
if (!payload || typeof payload !== 'object')
|
||
return payload
|
||
|
||
const { code, data, message } = payload
|
||
|
||
if (code == null || code === '')
|
||
return payload
|
||
|
||
// 兼容 code 为字符串 "1000"
|
||
const numericCode = Number(code)
|
||
if (numericCode === 1000) {
|
||
if (Array.isArray(data)) {
|
||
// transfter(data, timezone.info);
|
||
} else if (data && data.list !== undefined && data.list?.length > 0) {
|
||
// transfter(data.list, timezone.info);
|
||
}
|
||
return data
|
||
}
|
||
|
||
return Promise.reject(new Error(message || '请求失败'))
|
||
}
|
||
|
||
// Add a response interceptor
|
||
request.interceptors.response.use(responseHandler, errorHandler)
|
||
|
||
export default request
|