| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- 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<never> {
- 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<void> {
- // 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();
|