/** * 增强的 API 请求工具 */ import axios, { AxiosRequestConfig, AxiosError } from 'axios'; import { apiPerformanceMonitor } from './performance'; import { memoryCache } from './cache-manager'; import { getToken } from './token-util'; import { API_BASE_URL, TOKEN_HEADER_NAME } from '@/config/setting'; // 请求配置接口 interface EnhancedRequestConfig extends AxiosRequestConfig { // 缓存配置 cache?: { enabled: boolean; expiry?: number; key?: string; tags?: string[]; }; // 重试配置 retry?: { times: number; delay: number; condition?: (error: AxiosError) => boolean; }; // 性能监控 performance?: boolean; // 请求去重 dedupe?: boolean; // 超时重试 timeoutRetry?: boolean; } // 请求队列管理 class RequestQueue { private pendingRequests = new Map>(); // 生成请求键 private generateKey(config: AxiosRequestConfig): string { const { method, url, params, data } = config; return `${method}_${url}_${JSON.stringify(params)}_${JSON.stringify(data)}`; } // 添加请求到队列 add(config: AxiosRequestConfig, executor: () => Promise): Promise { const key = this.generateKey(config); if (this.pendingRequests.has(key)) { return this.pendingRequests.get(key); } const promise = executor().finally(() => { this.pendingRequests.delete(key); }); this.pendingRequests.set(key, promise); return promise; } // 清除队列 clear(): void { this.pendingRequests.clear(); } } // 重试机制 class RetryManager { static async retry( fn: () => Promise, config: { times: number; delay: number; condition?: (error: any) => boolean } ): Promise { let lastError: any; for (let i = 0; i <= config.times; i++) { try { return await fn(); } catch (error) { lastError = error; // 检查是否应该重试 if (i < config.times && (!config.condition || config.condition(error as AxiosError))) { await this.delay(config.delay * Math.pow(2, i)); // 指数退避 console.warn(`请求重试 ${i + 1}/${config.times}:`, error); } else { break; } } } throw lastError; } private static delay(ms: number): Promise { return new Promise(resolve => setTimeout(resolve, ms)); } } // 增强的请求类 export class EnhancedRequest { private instance = axios.create({ baseURL: API_BASE_URL, timeout: 30000 }); private requestQueue = new RequestQueue(); constructor() { this.setupInterceptors(); } private setupInterceptors() { // 请求拦截器 this.instance.interceptors.request.use( (config) => { // 添加认证头 const token = getToken(); if (token && config.headers) { config.headers[TOKEN_HEADER_NAME] = token; } // 添加请求时间戳 (config as any).startTime = Date.now(); return config; }, (error) => { return Promise.reject(error); } ); // 响应拦截器 this.instance.interceptors.response.use( (response) => { // 记录性能数据 const config = response.config as any; if (config.startTime) { const duration = Date.now() - config.startTime; apiPerformanceMonitor.recordApiCall(config.url, duration); } return response; }, (error) => { // 记录错误的性能数据 const config = error.config as any; if (config && config.startTime) { const duration = Date.now() - config.startTime; apiPerformanceMonitor.recordApiCall(config.url, duration); } return Promise.reject(error); } ); } // 通用请求方法 async request(config: EnhancedRequestConfig): Promise { const { cache, retry, performance = true, dedupe = true, timeoutRetry = true, ...axiosConfig } = config; // 生成缓存键 const cacheKey = cache?.key || this.generateCacheKey(axiosConfig); // 尝试从缓存获取 if (cache?.enabled) { const cachedData = memoryCache.get(cacheKey); if (cachedData !== null) { return cachedData; } } // 请求执行器 const executor = async (): Promise => { const response = await this.instance.request(axiosConfig); // 缓存响应数据 if (cache?.enabled && response.data) { memoryCache.set( cacheKey, response.data, cache.expiry, cache.tags ); } return response.data; }; // 请求去重 if (dedupe) { return this.requestQueue.add(axiosConfig, async () => { // 重试机制 if (retry) { return RetryManager.retry(executor, { ...retry, condition: retry.condition || this.shouldRetry }); } return executor(); }); } // 重试机制 if (retry) { return RetryManager.retry(executor, { ...retry, condition: retry.condition || this.shouldRetry }); } return executor(); } // GET 请求 get(url: string, config?: EnhancedRequestConfig): Promise { return this.request({ ...config, method: 'GET', url }); } // POST 请求 post(url: string, data?: any, config?: EnhancedRequestConfig): Promise { return this.request({ ...config, method: 'POST', url, data }); } // PUT 请求 put(url: string, data?: any, config?: EnhancedRequestConfig): Promise { return this.request({ ...config, method: 'PUT', url, data }); } // DELETE 请求 delete(url: string, config?: EnhancedRequestConfig): Promise { return this.request({ ...config, method: 'DELETE', url }); } // 批量请求 async batch(requests: EnhancedRequestConfig[]): Promise { const promises = requests.map(config => this.request(config)); return Promise.all(promises); } // 并发控制请求 async concurrent( requests: EnhancedRequestConfig[], limit: number = 5 ): Promise { const results: T[] = []; for (let i = 0; i < requests.length; i += limit) { const batch = requests.slice(i, i + limit); const batchResults = await this.batch(batch); results.push(...batchResults); } return results; } // 生成缓存键 private generateCacheKey(config: AxiosRequestConfig): string { const { method, url, params, data } = config; return `api_${method}_${url}_${JSON.stringify(params)}_${JSON.stringify(data)}`; } // 判断是否应该重试 private shouldRetry(error: AxiosError): boolean { // 网络错误或超时错误重试 if (!error.response) { return true; } // 5xx 服务器错误重试 const status = error.response.status; return status >= 500 && status < 600; } // 清除缓存 clearCache(tags?: string[]): void { if (tags) { memoryCache.clearByTags(tags); } else { memoryCache.clear(); } } // 取消所有请求 cancelAll(): void { this.requestQueue.clear(); } } // 全局实例 export const enhancedRequest = new EnhancedRequest(); // 便捷方法 export const { get, post, put, delete: del, batch, concurrent } = enhancedRequest; // 带缓存的 GET 请求 export function cachedGet( url: string, config?: Omit & { expiry?: number; tags?: string[]; } ): Promise { const { expiry = 5 * 60 * 1000, tags, ...restConfig } = config || {}; return enhancedRequest.get(url, { ...restConfig, cache: { enabled: true, expiry, tags } }); } // 带重试的请求 export function retryRequest( config: EnhancedRequestConfig, retryTimes: number = 3, retryDelay: number = 1000 ): Promise { return enhancedRequest.request({ ...config, retry: { times: retryTimes, delay: retryDelay } }); }