import { ApiError } from '@typings/api'; const BASE_URL = '/api'; const DEFAULT_TIMEOUT = 30000; interface RequestOptions { method?: 'GET' | 'POST' | 'PUT' | 'DELETE'; body?: any; headers?: Record; timeout?: number; } class ApiClient { private baseUrl: string; constructor(baseUrl: string = BASE_URL) { this.baseUrl = baseUrl; } private async handleResponse(response: Response): Promise { if (!response.ok) { let errorMessage = '请求失败'; if (response.status === 401) { errorMessage = '未授权,请重新登录'; } else if (response.status === 403) { errorMessage = '没有权限执行此操作'; } else if (response.status === 404) { errorMessage = '请求的资源不存在'; } else if (response.status >= 500) { errorMessage = '服务器错误,请稍后重试'; } else { try { const errorData = await response.json(); errorMessage = errorData.detail || errorData.message || errorMessage; } catch { // 无法解析错误详情 } } throw new ApiError(response.status, errorMessage); } const contentType = response.headers.get('content-type'); if (contentType?.includes('application/json')) { return response.json(); } return {} as T; } async request(path: string, options: RequestOptions = {}): Promise { const { method = 'GET', body, headers = {}, timeout = DEFAULT_TIMEOUT } = options; const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), timeout); const config: RequestInit = { method, headers: { 'Content-Type': 'application/json', ...headers, }, signal: controller.signal, }; if (body && method !== 'GET') { config.body = JSON.stringify(body); } try { const response = await fetch(`${this.baseUrl}${path}`, config); clearTimeout(timeoutId); return this.handleResponse(response); } catch (error: any) { clearTimeout(timeoutId); if (error.name === 'AbortError') { throw new ApiError(0, '请求超时,请检查网络连接'); } if (!error.status) { throw new ApiError(0, '网络错误,请检查网络连接'); } throw error; } } async get(path: string): Promise { return this.request(path); } async post(path: string, body?: any): Promise { return this.request(path, { method: 'POST', body }); } async put(path: string, body?: any): Promise { return this.request(path, { method: 'PUT', body }); } async delete(path: string): Promise { return this.request(path, { method: 'DELETE' }); } async upload(path: string, formData: FormData): Promise { const response = await fetch(`${this.baseUrl}${path}`, { method: 'POST', body: formData, }); return this.handleResponse(response); } } export const apiClient = new ApiClient();