MCPcopy Create free account
hub / github.com/VirtualHotBar/NetMount / robustFetch

Function robustFetch

src/utils/request.ts:131–269  ·  view source on GitHub ↗
(
  url: string,
  options: RequestInit = {},
  config: RequestConfig = {}
)

Source from the content-addressed store, hash-verified

129 * @returns 请求结果
130 */
131export async function robustFetch<T = unknown>(
132 url: string,
133 options: RequestInit = {},
134 config: RequestConfig = {}
135): Promise<RequestResult<T>> {
136 const {
137 timeout = API_TIMEOUT.DEFAULT,
138 retries = RETRY_CONFIG.MAX_ATTEMPTS,
139 retryDelay = RETRY_CONFIG.INITIAL_DELAY,
140 retryOnTimeout = true,
141 abortSignal,
142 headers = {},
143 } = config
144
145 const startTime = Date.now()
146 let lastError: AppError | undefined
147 let attempts = 0
148
149 try {
150 // 重试循环
151 while (attempts < retries) {
152 attempts++
153
154 try {
155 // 如果外部已取消,直接终止
156 if (abortSignal?.aborted) {
157 lastError = AppError.network('请求被中止')
158 break
159 }
160
161 const controller = new AbortController()
162
163 // 超时控制(每次尝试独立计时)
164 const timeoutId = setTimeout(() => controller.abort(), timeout)
165
166 // 监听外部 abort
167 const onAbort = () => {
168 controller.abort()
169 }
170 abortSignal?.addEventListener('abort', onAbort)
171
172 // 合并 headers:默认值 < options.headers < config.headers
173 const mergedHeaders: Record<string, string> = {
174 'Content-Type': 'application/json',
175 ...normalizeHeaders(options.headers),
176 ...headers,
177 }
178
179 let response: Response
180 try {
181 response = await fetch(url, {
182 ...options,
183 headers: mergedHeaders,
184 signal: controller.signal,
185 })
186 } finally {
187 clearTimeout(timeoutId)
188 abortSignal?.removeEventListener('abort', onAbort)

Callers 3

robustGetFunction · 0.85
robustPostFunction · 0.85
robustDeleteFunction · 0.85

Calls 6

normalizeHeadersFunction · 0.85
shouldRetryFunction · 0.85
calculateRetryDelayFunction · 0.85
networkMethod · 0.80
apiMethod · 0.80
timeoutMethod · 0.80

Tested by

no test coverage detected