|
|
|
@ -11,6 +11,9 @@ import {
|
|
|
|
|
DEFAULT_HEADERS, |
|
|
|
|
STORAGE_KEYS, |
|
|
|
|
} from "../../constants/config"; |
|
|
|
|
import { Platform } from "react-native"; |
|
|
|
|
// import https from 'https';
|
|
|
|
|
// import { Platform } from "react-native";
|
|
|
|
|
|
|
|
|
|
// 定义响应类型接口
|
|
|
|
|
export interface ApiResponse<T = any> { |
|
|
|
@ -27,6 +30,12 @@ export interface ApiError {
|
|
|
|
|
data?: any; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 扩展 AxiosRequestConfig 类型
|
|
|
|
|
interface CustomAxiosRequestConfig extends InternalAxiosRequestConfig { |
|
|
|
|
retry?: number; |
|
|
|
|
retryDelay?: (retryCount: number) => number; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 创建axios实例
|
|
|
|
|
const apiClient: AxiosInstance = axios.create({ |
|
|
|
|
baseURL: API_BASE_URL, |
|
|
|
@ -34,11 +43,26 @@ const apiClient: AxiosInstance = axios.create({
|
|
|
|
|
headers: DEFAULT_HEADERS, |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
// if (__DEV__ && Platform.OS === "android") {
|
|
|
|
|
// apiClient.defaults.httpsAgent = new https.Agent({ rejectUnauthorized: false });
|
|
|
|
|
// }
|
|
|
|
|
// 请求拦截器
|
|
|
|
|
apiClient.interceptors.request.use( |
|
|
|
|
async (config: InternalAxiosRequestConfig) => { |
|
|
|
|
const fullUrl = `${config.baseURL}${config.url}`; |
|
|
|
|
console.log("完整请求地址:", fullUrl); // 例如: https://api.example.com/api/user
|
|
|
|
|
const baseUrl = config.baseURL || ''; |
|
|
|
|
let fullUrl = baseUrl + config.url; |
|
|
|
|
if (config.params) { |
|
|
|
|
const params = new URLSearchParams(config.params); |
|
|
|
|
fullUrl += (fullUrl.includes('?') ? '&' : '?') + params.toString(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// console.log("环境:", __DEV__ ? "开发环境" : "生产环境");
|
|
|
|
|
// console.log("平台:", Platform.OS);
|
|
|
|
|
// console.log("请求方法:", config.method);
|
|
|
|
|
// console.log("完整URL:", fullUrl);
|
|
|
|
|
// console.log("请求头:", config.headers);
|
|
|
|
|
// console.log("请求参数:", config.params);
|
|
|
|
|
// console.log("请求数据:", config.data);
|
|
|
|
|
|
|
|
|
|
// 从AsyncStorage获取token
|
|
|
|
|
const token = await AsyncStorage.getItem("token"); |
|
|
|
@ -49,6 +73,7 @@ apiClient.interceptors.request.use(
|
|
|
|
|
return config; |
|
|
|
|
}, |
|
|
|
|
(error: AxiosError) => { |
|
|
|
|
console.error("请求拦截器错误:", error); |
|
|
|
|
return Promise.reject(error); |
|
|
|
|
} |
|
|
|
|
); |
|
|
|
@ -57,19 +82,53 @@ apiClient.interceptors.request.use(
|
|
|
|
|
apiClient.interceptors.response.use( |
|
|
|
|
(response: AxiosResponse) => { |
|
|
|
|
// 成功响应处理
|
|
|
|
|
// console.log("响应成功:", {
|
|
|
|
|
// status: response.status,
|
|
|
|
|
// statusText: response.statusText,
|
|
|
|
|
// headers: response.headers,
|
|
|
|
|
// data: response.data,
|
|
|
|
|
// });
|
|
|
|
|
return response; |
|
|
|
|
}, |
|
|
|
|
async (error: AxiosError<any>) => { |
|
|
|
|
// 错误响应处理
|
|
|
|
|
const { response } = error; |
|
|
|
|
const { response, config } = error; |
|
|
|
|
console.error("响应错误:", { |
|
|
|
|
status: response?.status, |
|
|
|
|
statusText: response?.statusText, |
|
|
|
|
data: response?.data, |
|
|
|
|
url: config?.url, |
|
|
|
|
method: config?.method, |
|
|
|
|
message: error.message, |
|
|
|
|
code: error.code, |
|
|
|
|
stack: error.stack, |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
// 处理网络错误
|
|
|
|
|
if (!response) { |
|
|
|
|
console.error("网络错误:", { |
|
|
|
|
message: error.message, |
|
|
|
|
code: error.code, |
|
|
|
|
stack: error.stack, |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
// 如果是网络错误,尝试重试
|
|
|
|
|
const customConfig = config as CustomAxiosRequestConfig; |
|
|
|
|
if (customConfig && customConfig.retry) { |
|
|
|
|
customConfig.retry -= 1; |
|
|
|
|
if (customConfig.retry > 0) { |
|
|
|
|
const delay = customConfig.retryDelay ? customConfig.retryDelay(customConfig.retry) : 1000; |
|
|
|
|
console.log(`重试请求 (${customConfig.retry}): ${customConfig.url}`); |
|
|
|
|
await new Promise(resolve => setTimeout(resolve, delay)); |
|
|
|
|
return apiClient(customConfig); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 处理401错误 (未授权)
|
|
|
|
|
if (response && response.status === 401) { |
|
|
|
|
// 清除存储的token
|
|
|
|
|
console.log("未授权错误,清除token"); |
|
|
|
|
await AsyncStorage.removeItem(STORAGE_KEYS.AUTH_TOKEN); |
|
|
|
|
|
|
|
|
|
// 这里可以添加重定向到登录页面的逻辑
|
|
|
|
|
// 例如使用事件发射器或全局状态管理
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 构建标准化的错误对象
|
|
|
|
@ -88,7 +147,12 @@ export const apiService = {
|
|
|
|
|
// GET请求
|
|
|
|
|
async get<T>(url: string, params?: any, config?: any): Promise<T> { |
|
|
|
|
try { |
|
|
|
|
const response = await apiClient.get<T>(url, { params, ...config }); |
|
|
|
|
const customConfig: CustomAxiosRequestConfig = { |
|
|
|
|
...config, |
|
|
|
|
retry: 3, |
|
|
|
|
retryDelay: (retryCount) => retryCount * 1000, |
|
|
|
|
}; |
|
|
|
|
const response = await apiClient.get<T>(url, { params, ...customConfig }); |
|
|
|
|
return response.data; |
|
|
|
|
} catch (error) { |
|
|
|
|
throw error; |
|
|
|
@ -98,7 +162,12 @@ export const apiService = {
|
|
|
|
|
// POST请求
|
|
|
|
|
async post<T>(url: string, data?: any, config?: any): Promise<T> { |
|
|
|
|
try { |
|
|
|
|
const response = await apiClient.post<T>(url, data, config); |
|
|
|
|
const customConfig: CustomAxiosRequestConfig = { |
|
|
|
|
...config, |
|
|
|
|
retry: 3, |
|
|
|
|
retryDelay: (retryCount) => retryCount * 1000, |
|
|
|
|
}; |
|
|
|
|
const response = await apiClient.post<T>(url, data, customConfig); |
|
|
|
|
return response.data; |
|
|
|
|
} catch (error) { |
|
|
|
|
throw error; |
|
|
|
@ -108,7 +177,12 @@ export const apiService = {
|
|
|
|
|
// PUT请求
|
|
|
|
|
async put<T>(url: string, data?: any, config?: any): Promise<T> { |
|
|
|
|
try { |
|
|
|
|
const response = await apiClient.put<T>(url, data, config); |
|
|
|
|
const customConfig: CustomAxiosRequestConfig = { |
|
|
|
|
...config, |
|
|
|
|
retry: 3, |
|
|
|
|
retryDelay: (retryCount) => retryCount * 1000, |
|
|
|
|
}; |
|
|
|
|
const response = await apiClient.put<T>(url, data, customConfig); |
|
|
|
|
return response.data; |
|
|
|
|
} catch (error) { |
|
|
|
|
throw error; |
|
|
|
@ -118,7 +192,12 @@ export const apiService = {
|
|
|
|
|
// PATCH请求
|
|
|
|
|
async patch<T>(url: string, data?: any, config?: any): Promise<T> { |
|
|
|
|
try { |
|
|
|
|
const response = await apiClient.patch<T>(url, data, config); |
|
|
|
|
const customConfig: CustomAxiosRequestConfig = { |
|
|
|
|
...config, |
|
|
|
|
retry: 3, |
|
|
|
|
retryDelay: (retryCount) => retryCount * 1000, |
|
|
|
|
}; |
|
|
|
|
const response = await apiClient.patch<T>(url, data, customConfig); |
|
|
|
|
return response.data; |
|
|
|
|
} catch (error) { |
|
|
|
|
throw error; |
|
|
|
@ -128,7 +207,12 @@ export const apiService = {
|
|
|
|
|
// DELETE请求
|
|
|
|
|
async delete<T>(url: string, config?: any): Promise<T> { |
|
|
|
|
try { |
|
|
|
|
const response = await apiClient.delete<T>(url, config); |
|
|
|
|
const customConfig: CustomAxiosRequestConfig = { |
|
|
|
|
...config, |
|
|
|
|
retry: 3, |
|
|
|
|
retryDelay: (retryCount) => retryCount * 1000, |
|
|
|
|
}; |
|
|
|
|
const response = await apiClient.delete<T>(url, customConfig); |
|
|
|
|
return response.data; |
|
|
|
|
} catch (error) { |
|
|
|
|
throw error; |
|
|
|
|