* 发送 HTTP 请求 * 自动处理重试、超时、错误
(path: string, options: RequestOptions = {})
| 87 | * 自动处理重试、超时、错误 |
| 88 | */ |
| 89 | protected async request<T>(path: string, options: RequestOptions = {}): Promise<T> { |
| 90 | const url = this.buildUrl(path, options.params); |
| 91 | const timeout = options.timeout ?? this.options.timeout; |
| 92 | |
| 93 | let lastError: Error | null = null; |
| 94 | const maxRetries = this.options.retry!.maxRetries!; |
| 95 | |
| 96 | // 重试循环 |
| 97 | for (let attempt = 0; attempt <= maxRetries; attempt++) { |
| 98 | try { |
| 99 | // 创建 AbortController 用于超时 |
| 100 | const controller = new AbortController(); |
| 101 | const timeoutId = setTimeout(() => controller.abort(), timeout); |
| 102 | |
| 103 | try { |
| 104 | const response = await this.fetchImpl(url, { |
| 105 | method: options.method ?? "GET", |
| 106 | headers: this.buildHeaders(options.headers), |
| 107 | body: options.body ? JSON.stringify(options.body) : undefined, |
| 108 | signal: options.signal ?? controller.signal, |
| 109 | }); |
| 110 | |
| 111 | clearTimeout(timeoutId); |
| 112 | |
| 113 | // 检查是否需要重试 |
| 114 | if (!response.ok && this.shouldRetry(response.status) && attempt < maxRetries) { |
| 115 | lastError = new Error(`HTTP ${response.status}: ${response.statusText}`); |
| 116 | await this.delay(this.getBackoffDelay(attempt)); |
| 117 | continue; |
| 118 | } |
| 119 | |
| 120 | // 处理响应 |
| 121 | return await this.handleResponse<T>(response); |
| 122 | } finally { |
| 123 | clearTimeout(timeoutId); |
| 124 | } |
| 125 | } catch (error: any) { |
| 126 | lastError = error; |
| 127 | |
| 128 | // 超时或网络错误,可以重试 |
| 129 | if (attempt < maxRetries && this.isRetryableError(error)) { |
| 130 | await this.delay(this.getBackoffDelay(attempt)); |
| 131 | continue; |
| 132 | } |
| 133 | |
| 134 | // 不可重试,直接抛出 |
| 135 | throw this.wrapError(error, path); |
| 136 | } |
| 137 | } |
| 138 | |
| 139 | // 所有重试都失败了 |
| 140 | throw this.wrapError(lastError!, path); |
| 141 | } |
| 142 | |
| 143 | /** |
| 144 | * 构建完整 URL |
no test coverage detected