import { Authorization } from '@/constants/authorization'; import type { ResponseType } from '@/interfaces/database/base'; import i18n from '@/locales'; import axios from 'axios'; import type { AxiosRequestConfig, AxiosInstance, AxiosResponse, InternalAxiosRequestConfig } from 'axios'; import { snackbar, notification } from '@/utils/snackbarInstance'; const FAILED_TO_FETCH = 'Failed to fetch'; export const RetcodeMessage = { 200: i18n.t('message.200'), 201: i18n.t('message.201'), 202: i18n.t('message.202'), 204: i18n.t('message.204'), 400: i18n.t('message.400'), 401: i18n.t('message.401'), 403: i18n.t('message.403'), 404: i18n.t('message.404'), 406: i18n.t('message.406'), 410: i18n.t('message.410'), 413: i18n.t('message.413'), 422: i18n.t('message.422'), 500: i18n.t('message.500'), 502: i18n.t('message.502'), 503: i18n.t('message.503'), 504: i18n.t('message.504'), }; export type ResultCode = | 200 | 201 | 202 | 204 | 400 | 401 | 403 | 404 | 406 | 410 | 413 | 422 | 500 | 502 | 503 | 504; // 获取授权token const getAuthorization = (): string => { return localStorage.getItem(Authorization) || ''; }; // 重定向到登录页 const redirectToLogin = (): void => { localStorage.removeItem(Authorization); window.location.href = '/login'; }; // 转换对象键为snake_case const convertTheKeysOfTheObjectToSnake = (obj: any): any => { if (!obj || typeof obj !== 'object') return obj; if (Array.isArray(obj)) { return obj.map(convertTheKeysOfTheObjectToSnake); } const result: any = {}; Object.keys(obj).forEach(key => { const snakeKey = key.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`); result[snakeKey] = convertTheKeysOfTheObjectToSnake(obj[key]); }); return result; }; // 创建axios实例 const request: AxiosInstance = axios.create({ baseURL: import.meta.env.VITE_API_BASE_URL, timeout: 300000, headers: { 'Content-Type': 'application/json', }, }); // 请求拦截器 request.interceptors.request.use( (config: InternalAxiosRequestConfig) => { // 转换数据格式 - 跳过FormData对象 if (config.data && !(config.data instanceof FormData)) { config.data = convertTheKeysOfTheObjectToSnake(config.data); } if (config.params) { config.params = convertTheKeysOfTheObjectToSnake(config.params); } // 对于FormData,删除默认的Content-Type让浏览器自动设置 if (config.data instanceof FormData) { delete config.headers['Content-Type']; } // 添加授权头 const authorization = getAuthorization(); if (authorization && !config.headers?.skipToken) { config.headers.Authorization = authorization; } return config; }, (error) => { return Promise.reject(error); } ); // 响应拦截器 request.interceptors.response.use( (response: AxiosResponse) => { const { status } = response; // 处理特定状态码 if (status === 413 || status === 504) { snackbar.error(RetcodeMessage[status as ResultCode]); } // 处理blob类型响应 if (response.config.responseType === 'blob') { return response; } console.log('interceptors.response ------ response', response); const data: ResponseType = response.data; // 处理业务错误码 if (data?.code === 100) { snackbar.error(data?.message); } else if (data?.code === 401) { notification.error(data?.message); redirectToLogin(); } else if (data?.code !== 0) { notification.error(`${i18n.t('message.hint')} : ${data?.code}`, data?.message); } return response; }, (error) => { // 处理网络错误 if (error.message === FAILED_TO_FETCH || !error.response) { notification.error(i18n.t('message.networkAnomaly'), i18n.t('message.networkAnomalyDescription')); } else if (error.response) { const { status, statusText } = error.response; const errorText = RetcodeMessage[status as ResultCode] || statusText; notification.error(`${i18n.t('message.requestError')} ${status}`, errorText); } return Promise.reject(error); } ); export default request; // 便捷方法 export const get = (url: string, config?: AxiosRequestConfig) => { return request.get(url, config); }; export const post = (url: string, data?: any, config?: AxiosRequestConfig) => { return request.post(url, data, config); }; export const put = (url: string, data?: any, config?: AxiosRequestConfig) => { return request.put(url, data, config); }; export const del = (url: string, config?: AxiosRequestConfig) => { return request.delete(url, config); };