Files
ece.suwa3d.com/src/utils/request.ts
T
2026-11-03 14:13:25 +08:00

137 lines
3.8 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 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