/** * Mono 级别的 C 端 Axios 实例 * 供 monorepo 中所有应用使用的统一 HTTP 客户端 */ import axios from 'axios' import { getAuthHeader, clearAllTokens } from '@gold/utils/token-manager' /** * 不需要 token 的接口白名单 */ const WHITE_LIST = [ '/auth/login', '/auth/send-sms-code', '/auth/sms-login', '/auth/validate-sms-code', '/auth/register', '/auth/reset-password', '/auth/refresh-token', ] /** * 检查 URL 是否在白名单中 */ function isInWhiteList(url) { if (!url) return false return WHITE_LIST.some((path) => url.includes(path)) } /** * 处理 401 未授权错误 */ let isHandling401 = false function handle401Error() { if (isHandling401) return isHandling401 = true try { clearAllTokens() } catch (e) { console.error('清空 token 失败:', e) } // 延迟重置标志 setTimeout(() => { isHandling401 = false }, 2000) } /** * 创建 C 端 Axios 实例 * @param {Object} options - 配置选项 * @param {string} options.baseURL - 基础 URL * @param {number} options.timeout - 超时时间(毫秒) * @param {Function} options.on401 - 401 错误处理函数 * @param {Function} options.on403 - 403 错误处理函数 * @returns {AxiosInstance} Axios 实例 */ export function createClientAxios(options = {}) { const { baseURL = '/', timeout = 180000, on401 = handle401Error, on403 = null, } = options const client = axios.create({ baseURL, timeout, }) // 请求拦截器 client.interceptors.request.use((config) => { // 添加 tenant-id const tenantId = (typeof import.meta !== 'undefined' && import.meta.env?.VITE_TENANT_ID) || (typeof process !== 'undefined' && process.env?.VITE_TENANT_ID) || '1' if (tenantId) { config.headers['tenant-id'] = tenantId } // 添加 Authorization header const needToken = config.headers?.isToken !== false && !isInWhiteList(config.url || '') if (needToken) { const authHeader = getAuthHeader() if (authHeader) { config.headers.Authorization = authHeader } } return config }) // 响应拦截器 client.interceptors.response.use( (response) => { const data = response.data // 检查业务状态码 if (data && typeof data.code === 'number') { if (data.code === 0 || data.code === 200) { return data } // 处理 401 if (data.code === 401 && typeof on401 === 'function') { on401() } // 处理 403(业务状态码) if (data.code === 403 && typeof on403 === 'function') { on403() } // 抛出业务错误 const error = new Error(data?.message || data?.msg || '请求失败') error.code = data?.code error.data = data return Promise.reject(error) } return data }, (error) => { // 处理 HTTP 401 if (error.response?.status === 401 && typeof on401 === 'function') { on401() } // 处理 HTTP 403 if (error.response?.status === 403 && typeof on403 === 'function') { on403() } return Promise.reject(error) } ) return client } /** * 默认导出的 C 端 Axios 实例 * 可在应用层覆盖配置 */ export const clientAxios = createClientAxios() export default clientAxios