request.ts 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. // utils/request.ts
  2. interface RequestOptions extends RequestInit {
  3. params?: Record<string, any>;
  4. timeout?: number;
  5. }
  6. class Request {
  7. private baseUrl: string;
  8. private timeout: number;
  9. constructor(baseUrl: string = '', timeout: number = 10000) {
  10. this.baseUrl = baseUrl;
  11. this.timeout = timeout;
  12. }
  13. private getUrl(url: string): string {
  14. if (url.startsWith('http')) return url;
  15. return this.baseUrl + url;
  16. }
  17. private async handleResponse(response: Response) {
  18. if (!response.ok) {
  19. throw new Error(`HTTP error! status: ${response.status}`);
  20. }
  21. return response.json();
  22. }
  23. private async withTimeout<T>(promise: Promise<T>, timeout: number): Promise<T> {
  24. return Promise.race([
  25. promise,
  26. new Promise<never>((_, reject) =>
  27. setTimeout(() => reject(new Error('Request timeout')), timeout)
  28. )
  29. ]);
  30. }
  31. async request<T = any>(url: string, options: RequestOptions = {}): Promise<T> {
  32. const {
  33. method = 'GET',
  34. headers = {},
  35. body,
  36. params,
  37. timeout = this.timeout,
  38. ...restOptions
  39. } = options;
  40. let fullUrl = this.getUrl(url);
  41. // 处理查询参数
  42. if (params) {
  43. const searchParams = new URLSearchParams(params);
  44. fullUrl += (fullUrl.includes('?') ? '&' : '?') + searchParams.toString();
  45. }
  46. const config: RequestInit = {
  47. method,
  48. headers: {
  49. 'Content-Type': 'application/json',
  50. ...headers
  51. },
  52. ...restOptions
  53. };
  54. if (body) {
  55. config.body = typeof body === 'string' ? body : JSON.stringify(body);
  56. }
  57. try {
  58. const response = await this.withTimeout(fetch(fullUrl, config), timeout);
  59. return await this.handleResponse(response);
  60. } catch (error) {
  61. throw error;
  62. }
  63. }
  64. get<T = any>(url: string, options?: Omit<RequestOptions, 'method'>) {
  65. return this.request<T>(url, { ...options, method: 'GET' });
  66. }
  67. post<T = any>(url: string, data?: any, options?: Omit<RequestOptions, 'method' | 'body'>) {
  68. return this.request<T>(url, {
  69. ...options,
  70. method: 'POST',
  71. body: data
  72. });
  73. }
  74. put<T = any>(url: string, data?: any, options?: Omit<RequestOptions, 'method' | 'body'>) {
  75. return this.request<T>(url, {
  76. ...options,
  77. method: 'PUT',
  78. body: data
  79. });
  80. }
  81. delete<T = any>(url: string, options?: Omit<RequestOptions, 'method'>) {
  82. return this.request<T>(url, { ...options, method: 'DELETE' });
  83. }
  84. }
  85. // 创建默认实例
  86. const request = new Request('https://usersource.landwu.com/api');
  87. export default request;