import axios, { type AxiosInstance, type CreateAxiosDefaults, type AxiosRequestConfig } from "axios" import { tokenManager } from "@/lib/auth/token" import { toast } from "sonner" import type { ApiResponse } from "@/types/api" import { API_STATUS, ApiError } from "@/types/api" import { type EncryptionConfig, DEFAULT_ENCRYPTION_CONFIG, encryptData, shouldEncryptRequest } from "@/lib/encryption/encryption" // 扩展 AxiosRequestConfig 以支持 ignoreError 选项 export interface ExtendedAxiosRequestConfig extends AxiosRequestConfig { ignoreError?: boolean } // 扩展 AxiosInstance 类型以支持带有 ignoreError 的请求 export interface ExtendedAxiosInstance extends AxiosInstance { post(url: string, data?: D, config?: ExtendedAxiosRequestConfig): Promise get(url: string, config?: ExtendedAxiosRequestConfig): Promise put(url: string, data?: D, config?: ExtendedAxiosRequestConfig): Promise delete(url: string, config?: ExtendedAxiosRequestConfig): Promise patch(url: string, data?: D, config?: ExtendedAxiosRequestConfig): Promise } export interface CreateHttpClientConfig extends CreateAxiosDefaults { serviceName: string baseURL?: string cookieString?: string // 用于服务端渲染时传递cookie showErrorToast?: boolean // 是否自动显示错误提示,默认为true encryption?: EncryptionConfig // 加密配置 } const endpoints = { frog: process.env.NEXT_PUBLIC_FROG_API_URL, bear: process.env.NEXT_PUBLIC_BEAR_API_URL, lion: process.env.NEXT_PUBLIC_LION_API_URL, shark: process.env.NEXT_PUBLIC_SHARK_API_URL, cow: process.env.NEXT_PUBLIC_COW_API_URL, pigeon: process.env.NEXT_PUBLIC_PIGEON_API_URL, } export function createHttpClient(config: CreateHttpClientConfig): ExtendedAxiosInstance { const { serviceName, baseURL, cookieString, showErrorToast = true, encryption = DEFAULT_ENCRYPTION_CONFIG, ...axiosConfig } = config // 从环境变量获取服务地址,如果没有则使用默认地址 const serviceBaseURL = endpoints[serviceName as keyof typeof endpoints] || baseURL || `http://localhost:3000/api/${serviceName}` const instance = axios.create({ baseURL: serviceBaseURL, timeout: 120000, headers: { "Content-Type": "application/json", "Platform": "web", "Versionnum": "100", }, ...axiosConfig }) // 请求拦截器 instance.interceptors.request.use( (config) => { // 获取token - 支持服务端和客户端 const token = tokenManager.getToken(cookieString) if (token) { // Java后端使用AUTH_TK字段接收token config.headers["AUTH_TK"] = token } config.headers["Accept-Language"] = "en"; // 获取设备ID - 支持服务端和客户端 const deviceId = tokenManager.getDeviceId(cookieString) if (deviceId) { // Java后端使用AUTH_DID字段接收设备ID config.headers["AUTH_DID"] = deviceId } // 添加服务标识 config.headers["X-Service"] = serviceName // 服务端渲染时,传递cookie if (typeof window === "undefined" && cookieString) { config.headers.Cookie = cookieString } // 加密处理 if (encryption.enabled && token && shouldEncryptRequest(config.data, encryption)) { try { console.log('config.data', config.data) // 加密请求数据 const encryptedData = encryptData(config.data, token, encryption) config.data = encryptedData // // 添加加密标识头 // config.headers[encryption.encryptHeader] = 'true' // 设置内容类型为JSON config.headers['Content-Type'] = 'application/json' } catch (error) { console.error('Request encryption failed:', error) // 加密失败时继续使用原始数据 } } return config }, (error) => { return Promise.reject(error) } ) // 响应拦截器 instance.interceptors.response.use( (response) => { const apiResponse = response.data as ApiResponse // 检查业务状态 if (apiResponse.status === API_STATUS.OK) { // 成功:返回content内容 return apiResponse.content } else { // 检查是否忽略错误 const ignoreError = (response.config as ExtendedAxiosRequestConfig)?.ignoreError // 业务错误:创建ApiError并抛出 const apiError = new ApiError( apiResponse.errorCode, apiResponse.errorMsg, apiResponse.traceId, !!ignoreError ) // 错误提示由providers.tsx中的全局错误处理统一管理 // 这里不再直接显示toast,避免重复弹窗 return Promise.reject(apiError) } }, (error) => { // 检查是否忽略错误 const ignoreError = (error.config as ExtendedAxiosRequestConfig)?.ignoreError // 网络错误或其他HTTP错误 let errorMessage = 'Network exception, please try again later' let errorCode = 'NETWORK_ERROR' // 创建标准化的错误对象 const traceId = error.response?.headers?.['x-trace-id'] || 'unknown' const apiError = new ApiError(errorCode, errorMessage, traceId, !!ignoreError) return Promise.reject(apiError) } ) return instance as ExtendedAxiosInstance } // 为服务端渲染创建带cookie的HTTP客户端 export function createServerHttpClient(serviceName: string, cookieString: string): ExtendedAxiosInstance { return createHttpClient({ serviceName, cookieString, showErrorToast: false // 服务端不显示toast }) } // 创建不显示错误提示的HTTP客户端(用于静默请求) export function createSilentHttpClient(serviceName: string): ExtendedAxiosInstance { return createHttpClient({ serviceName, showErrorToast: false }) }