import axios, { AxiosError } from 'axios' import { appEnv } from '@/config/env' import type { ApiResult } from '@/types/http' import { BizError } from '@/types/http' import { redirectToLogin } from '@/utils/auth-session' import { appMessage } from '@/utils/message' import { useAuthStore } from '@/stores/auth' const AUTH_ERROR_CODES = new Set([ 'AUTH.UNAUTHORIZED', 'AUTH.TOKEN_VERSION_INVALID', 'AUTH.USER_DISABLED', 'AUTH.USERNAME_OR_PASSWORD_INVALID' ]) const http = axios.create({ baseURL: appEnv.apiBaseUrl, timeout: 15000 }) http.interceptors.request.use((config) => { const authStore = useAuthStore() const token = authStore.token if (token) { config.headers.Authorization = `Bearer ${token}` } return config }) http.interceptors.response.use( async (response) => { const payload = response.data as ApiResult const traceId = response.headers['x-trace-id'] as string | undefined if (!payload || typeof payload.code !== 'string') { return response.data } if (payload.code === '0') { return payload.data } const errorMessage = payload.message || '请求失败' const resolvedTraceId = payload.traceId ?? traceId if (AUTH_ERROR_CODES.has(payload.code)) { await redirectToLogin('expired') appMessage.warning(errorMessage) throw new BizError(payload.code, errorMessage, resolvedTraceId) } appMessage.error( resolvedTraceId ? `${errorMessage}(追踪ID:${resolvedTraceId})` : errorMessage ) throw new BizError(payload.code, errorMessage, resolvedTraceId) }, async (error: AxiosError>) => { const status = error.response?.status const traceId = (error.response?.headers?.['x-trace-id'] as string | undefined) ?? error.response?.data?.traceId const backendMessage = error.response?.data?.message if (status === 401) { const errorMessage = backendMessage ?? '未登录或登录已失效,请重新登录' await redirectToLogin('expired') appMessage.warning(errorMessage) return Promise.reject(new BizError('401', errorMessage, traceId)) } if (status === 403) { const errorMessage = backendMessage ?? '无权限访问该资源' console.warn('[HTTP] 收到 403 响应', { url: error.config?.url, message: backendMessage }) appMessage.error(errorMessage) return Promise.reject(new BizError('403', errorMessage, traceId)) } const errorMessage = backendMessage ?? error.message ?? '网络异常,请稍后重试' appMessage.error(traceId ? `${errorMessage}(追踪ID:${traceId})` : errorMessage) return Promise.reject(new BizError(String(status ?? 'HTTP_ERROR'), errorMessage, traceId)) } ) export default http