File size: 3,086 Bytes
d0c18f0 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | import { ApiError } from '@typings/api';
const BASE_URL = '/api';
const DEFAULT_TIMEOUT = 30000;
interface RequestOptions {
method?: 'GET' | 'POST' | 'PUT' | 'DELETE';
body?: any;
headers?: Record<string, string>;
timeout?: number;
}
class ApiClient {
private baseUrl: string;
constructor(baseUrl: string = BASE_URL) {
this.baseUrl = baseUrl;
}
private async handleResponse<T>(response: Response): Promise<T> {
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<T>(path: string, options: RequestOptions = {}): Promise<T> {
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<T>(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<T>(path: string): Promise<T> {
return this.request<T>(path);
}
async post<T>(path: string, body?: any): Promise<T> {
return this.request<T>(path, { method: 'POST', body });
}
async put<T>(path: string, body?: any): Promise<T> {
return this.request<T>(path, { method: 'PUT', body });
}
async delete<T>(path: string): Promise<T> {
return this.request<T>(path, { method: 'DELETE' });
}
async upload<T>(path: string, formData: FormData): Promise<T> {
const response = await fetch(`${this.baseUrl}${path}`, {
method: 'POST',
body: formData,
});
return this.handleResponse<T>(response);
}
}
export const apiClient = new ApiClient(); |