apiClient.ts 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import { API_BASE_URL } from '../utils/constants';
  2. interface ApiResponse<T = any> {
  3. data: T;
  4. status: number;
  5. }
  6. class ApiClient {
  7. private baseURL: string;
  8. constructor(baseURL: string) {
  9. this.baseURL = baseURL;
  10. }
  11. private getAuthHeaders(): Record<string, string> {
  12. const token = localStorage.getItem('authToken') || localStorage.getItem('token');
  13. // console.log('API 调用 token:', token ? token.substring(0, 10) + '...' : 'null');
  14. return {
  15. 'Content-Type': 'application/json',
  16. ...(token && { Authorization: `Bearer ${token}` }),
  17. };
  18. }
  19. // 新式的 API 调用方法,返回 { data, status }
  20. async get<T = any>(url: string): Promise<ApiResponse<T>> {
  21. const response = await fetch(`${this.baseURL}${url}`, {
  22. method: 'GET',
  23. headers: this.getAuthHeaders(),
  24. });
  25. if (!response.ok) {
  26. const errorData = await response.json();
  27. throw new Error(errorData.message || 'Request failed');
  28. }
  29. const data = await response.json();
  30. return { data, status: response.status };
  31. }
  32. async post<T = any>(url: string, body?: any): Promise<ApiResponse<T>> {
  33. const response = await fetch(`${this.baseURL}${url}`, {
  34. method: 'POST',
  35. headers: this.getAuthHeaders(),
  36. body: body ? JSON.stringify(body) : undefined,
  37. });
  38. if (!response.ok) {
  39. const errorData = await response.json();
  40. throw new Error(errorData.message || 'Request failed');
  41. }
  42. const data = await response.json();
  43. return { data, status: response.status };
  44. }
  45. async put<T = any>(url: string, body?: any): Promise<ApiResponse<T>> {
  46. const response = await fetch(`${this.baseURL}${url}`, {
  47. method: 'PUT',
  48. headers: this.getAuthHeaders(),
  49. body: body ? JSON.stringify(body) : undefined,
  50. });
  51. if (!response.ok) {
  52. const errorData = await response.json();
  53. throw new Error(errorData.message || 'Request failed');
  54. }
  55. const data = await response.json();
  56. return { data, status: response.status };
  57. }
  58. async delete<T = any>(url: string): Promise<ApiResponse<T>> {
  59. const response = await fetch(`${this.baseURL}${url}`, {
  60. method: 'DELETE',
  61. headers: this.getAuthHeaders(),
  62. });
  63. if (!response.ok) {
  64. const errorData = await response.json();
  65. throw new Error(errorData.message || 'Request failed');
  66. }
  67. const data = await response.json();
  68. return { data, status: response.status };
  69. }
  70. // 保持原有的 API 兼容性方法,接受路径和选项参数并返回原始 Response
  71. async request(path: string, options: RequestInit = {}): Promise<Response> {
  72. const token = localStorage.getItem('authToken');
  73. const headers = new Headers(options.headers);
  74. if (token) {
  75. headers.set('Authorization', `Bearer ${token}`);
  76. }
  77. // 构建完整 URL
  78. let url = path;
  79. if (!path.startsWith('http')) {
  80. const cleanPath = path.startsWith('/') ? path : `/${path}`;
  81. url = `${this.baseURL}${cleanPath}`;
  82. }
  83. const response = await fetch(url, {
  84. ...options,
  85. headers,
  86. });
  87. if (response.status === 401) {
  88. localStorage.removeItem('authToken');
  89. window.location.reload();
  90. throw new Error('Unauthorized');
  91. }
  92. return response;
  93. }
  94. }
  95. export const apiClient = new ApiClient(API_BASE_URL);