import { Alert } from 'react-native'; import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError, InternalAxiosRequestConfig } from 'axios'; import {API_CONFIG, BaseResponse, ErrorResponse, ExtendedRequestConfig, RequestConfig } from './conf'; import * as SecureStore from 'expo-secure-store'; declare module 'axios' { interface AxiosRequestConfig { customConfig?: RequestConfig; } } // 创建 Axios 实例 class ApiClient { public instance: AxiosInstance; private isRefreshing = false; private failedQueue: Array<{ resolve: (value: any) => void; reject: (error: any) => void }> = []; constructor() { this.instance = axios.create({ baseURL: API_CONFIG.BASE_URL, timeout: API_CONFIG.TIMEOUT, headers: { 'Content-Type': 'application/json', }, }); this.setupInterceptors(); } // 设置拦截器 private setupInterceptors(): void { // 请求拦截器 this.instance.interceptors.request.use( async (config: InternalAxiosRequestConfig) => { const extendedConfig = config as InternalAxiosRequestConfig & { customConfig?: RequestConfig }; const { needAuth = true, token = null } = extendedConfig.customConfig || {}; // 添加认证令牌 if (needAuth) { const tokenStr = token? token : await SecureStore.getItemAsync('accessToken') if (tokenStr) { config.headers.Authorization = `Bearer ${tokenStr}`; } } return config; }, (error: AxiosError) => { console.error('❌ 请求错误:', error); return Promise.reject(error); } ); // 响应拦截器 this.instance.interceptors.response.use( (response: AxiosResponse) => { console.log(`✅ ${response.config.method?.toUpperCase()} ${response.config.url} 成功`); return response; }, async (error: AxiosError) => { return this.handleError(error); } ); } // 错误处理 private async handleError(error: AxiosError): Promise { const originalRequest = error.config as InternalAxiosRequestConfig & { _retry?: boolean; customConfig?: RequestConfig; }; // 网络错误 if (!error.response) { const networkError: ErrorResponse = { code: -1, message: API_CONFIG.ERROR_MESSAGES.NETWORK_ERROR, }; return Promise.reject(networkError); } const { status, data } = error.response; const errorData = data as ErrorResponse; // Token 过期,尝试刷新 if (status === 401 && !originalRequest._retry) { if (this.isRefreshing) { // 如果正在刷新,将请求加入队列 return new Promise((resolve, reject) => { this.failedQueue.push({ resolve, reject }); }); } originalRequest._retry = true; this.isRefreshing = true; try { // // 刷新 Token 逻辑 // await this.refreshToken(); // // 重试原始请求 // const retryResponse = await this.instance(originalRequest); // this.isRefreshing = false; // this.processQueue(null); // return retryResponse; } catch (refreshError) { this.isRefreshing = false; this.processQueue(refreshError); // 刷新失败,跳转到登录页 // await authManager.clearTokens(); // navigation.navigate('Login'); // 根据实际导航库调整 return Promise.reject({ code: 401, message: API_CONFIG.ERROR_MESSAGES.UNAUTHORIZED, }); } } console.log('响应错误:', errorData); // 其他错误处理 const customError: ErrorResponse = { code: status, message: errorData?.message || this.getErrorMessageByStatus(status), }; // 根据配置决定是否显示错误提示 const { showError = true } = originalRequest.customConfig || {}; if (showError) { this.showErrorToast(customError.message); } return Promise.reject(customError); } // 处理请求队列 private processQueue(error: any): void { this.failedQueue.forEach(promise => { if (error) { promise.reject(error); } else { promise.resolve(this.instance); } }); this.failedQueue = []; } // 刷新 Token // private async refreshToken(): Promise { // const refreshToken = await authManager.getRefreshToken(); // if (!refreshToken) { // throw new Error('No refresh token'); // } // // 调用刷新 Token 接口 // const response = await axios.post(`${API_CONFIG.BASE_URL}/auth/refresh`, { // refreshToken, // }); // const newTokens = response.data.data; // await authManager.setTokens(newTokens); // } // 根据状态码获取错误消息 private getErrorMessageByStatus(status: number): string { const messages: { [key: number]: string } = { 400: '请求参数错误', 403: '没有权限访问', 404: '请求资源不存在', 500: API_CONFIG.ERROR_MESSAGES.SERVER_ERROR, 502: '网关错误', 503: '服务不可用', 504: '网关超时', }; return messages[status] || `请求失败 (${status})`; } // 显示错误提示(可根据实际使用的 Toast 库调整) private showErrorToast(message: string): void { // 使用你喜欢的 Toast 库,例如 react-native-toast-message // Alert.alert('Error', message); // console.error('Error:', message); } } export const apiClient = new ApiClient();