From 1e537cf85d347b24a5a397c075ba9f70095a804d Mon Sep 17 00:00:00 2001 From: Yun Shan Date: Fri, 6 Sep 2024 17:27:00 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=AF=B7=E6=B1=82=E9=87=8D?= =?UTF-8?q?=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/request/index.ts | 84 +++++++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 33 deletions(-) diff --git a/src/request/index.ts b/src/request/index.ts index d910405..87a1e3d 100644 --- a/src/request/index.ts +++ b/src/request/index.ts @@ -37,6 +37,10 @@ export interface CommonRequestOptions extends RequestInit { * 请求超时时间 */ timeout?: number; + /** + * 最大重试次数 + */ + maxRetry?: number; useDefaultUserAgent?: boolean; responseTransformer?: (response: Response) => Promise; } @@ -73,42 +77,56 @@ function createRequest(reqUrl: string | URL, options: CommonRequestO * @returns 响应内容 */ async function request(url: string | URL, options: CommonRequestOptions = { method: 'GET' }): Promise { - let { timeout } = options; + const { timeout = 120 * 1000, maxRetry = 0 } = options; let timeoutId: ReturnType | undefined; - if (!timeout) { - // 默认超时120秒 - timeout = 120 * 1000; - } - if (Number.isSafeInteger(timeout) && timeout > 0) { - // 这里用AbortSignal.timeout这个静态方法更简洁,但是浏览器至少是22年5月的版本才兼容这个方法,而且IDE似乎也不能识别这个方法(可能是哪里的设置没有用最新js版本?) - const controller = new AbortController(); - options.signal = controller.signal; - timeoutId = setTimeout(() => { - controller.abort(); - }, timeout); + const doReq = async () => { + if (Number.isSafeInteger(timeout) && timeout > 0) { + // 这里用AbortSignal.timeout这个静态方法更简洁,但是浏览器至少是22年5月的版本才兼容这个方法,而且IDE似乎也不能识别这个方法(可能是哪里的设置没有用最新js版本?) + const controller = new AbortController(); + options.signal = controller.signal; + timeoutId = setTimeout(() => { + controller.abort(); + }, timeout); + } + const request = createRequest(url, options); + return await fetch(request) + .then((res) => { + if (!res.ok) { + throw new RequestError('获取响应失败,可能是临时网络波动,如果长时间失败请联系开发者', res); + } + if (options.responseTransformer) { + return options.responseTransformer(res); + } + return defaultResponseTransformer(res) as unknown as T; + }) + .catch((err: Error) => { + if (err.name === 'AbortError') { + throw new RequestError(`请求超时,强制停止请求(${String(timeout)}ms)`); + } + throw err; + }) + .finally(() => { + if (typeof timeoutId !== 'undefined') { + clearTimeout(timeoutId); + } + }); } - const request = createRequest(url, options); - return await fetch(request) - .then((res) => { - if (!res.ok) { - throw new RequestError('获取响应失败,可能是临时网络波动,如果长时间失败请联系开发者', res); - } - if (options.responseTransformer) { - return options.responseTransformer(res); + if (Number.isSafeInteger(maxRetry) && maxRetry > 0) { + let counter = 0; + // eslint-disable-next-line no-constant-condition + while (true) { + counter++; + try { + return await doReq(); + } catch (e) { + if (counter > maxRetry) { + throw e; + } } - return defaultResponseTransformer(res) as unknown as T; - }) - .catch((err: Error) => { - if (err.name === 'AbortError') { - throw new RequestError(`请求超时,强制停止请求(${String(timeout)}ms)`); - } - throw err; - }) - .finally(() => { - if (typeof timeoutId !== 'undefined') { - clearTimeout(timeoutId); - } - }); + } + } else { + return await doReq(); + } } /**