JS+Fetch
在 JavaScript 中,我们可以使用 fetch
API 来封装一个带有超时和重试功能的请求方法。以下是一个示例代码:
封装代码
javascript
/**
* 带有超时和重试功能的请求方法
* @param {string} url - 请求的URL
* @param {Object} options - fetch的配置选项
* @param {number} timeout - 超时时间(毫秒)
* @param {number} maxRetries - 最大重试次数
* @returns {Promise<Response>} - 返回fetch的响应
*/
async function fetchWithRetry(url, options = {}, timeout = 5000, maxRetries = 3) {
let retries = 0;
while (retries < maxRetries) {
try {
// 创建一个超时控制器
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
// 发起请求
const response = await fetch(url, {
...options,
signal: controller.signal, // 绑定超时控制器
});
// 清除超时计时器
clearTimeout(timeoutId);
// 如果响应状态码不是2xx,抛出错误
if (!response.ok) {
throw new Error(`请求失败,状态码: ${response.status}`);
}
// 返回响应
return response;
} catch (error) {
retries++;
console.warn(`请求失败,重试次数: ${retries}, 错误: ${error.message}`);
// 如果达到最大重试次数,抛出错误
if (retries >= maxRetries) {
throw new Error(`请求失败,已达到最大重试次数: ${maxRetries}`);
}
}
}
}
// 使用示例
(async () => {
try {
const url = "https://jsonplaceholder.typicode.com/posts/1";
const response = await fetchWithRetry(url, {}, 2000, 3); // 超时2秒,最大重试3次
const data = await response.json();
console.log("请求成功:", data);
} catch (error) {
console.error("请求最终失败:", error.message);
}
})();
代码说明:
-
超时控制:
- 使用
AbortController
和setTimeout
实现请求超时功能。 - 如果请求超时,调用
controller.abort()
中断请求。
- 使用
-
重试机制:
- 使用
while
循环和retries
计数器实现重试逻辑。 - 如果请求失败(超时或响应状态码非2xx),则重试,直到达到最大重试次数。
- 使用
-
错误处理:
- 如果请求失败,会抛出错误并重试。
- 如果达到最大重试次数,抛出最终错误。
-
使用示例:
- 调用
fetchWithRetry
方法时,传入 URL、配置选项、超时时间和最大重试次数。 - 请求成功后,返回响应数据;失败后,抛出错误。
- 调用
示例输出:
-
如果请求成功:
css请求成功: { userId: 1, id: 1, title: "...", body: "..." }
-
如果请求失败:
makefile请求失败,重试次数: 1, 错误: Request failed, status code: 500 请求失败,重试次数: 2, 错误: Request failed, status code: 500 请求失败,重试次数: 3, 错误: Request failed, status code: 500 请求最终失败: 请求失败,已达到最大重试次数: 3
注意事项:
-
浏览器兼容性:
AbortController
和fetch
在现代浏览器中支持良好,但在旧版浏览器中可能需要 polyfill。- 如果需要兼容旧版浏览器,可以使用
axios
库替代fetch
。
-
重试间隔:
- 当前代码是立即重试。如果需要增加重试间隔,可以在
catch
块中添加await new Promise(resolve => setTimeout(resolve, delay))
。
- 当前代码是立即重试。如果需要增加重试间隔,可以在
-
性能优化:
- 如果请求失败的原因是服务器过载,建议增加指数退避策略(Exponential Backoff)来避免加重服务器负担。
Promise.race() + Fetch
以下是使用 JavaScript 和 Promise
封装的一个带有 超时 和 重试 功能的请求方法。这个方法基于 fetch
API,并利用 Promise
实现超时控制和重试逻辑。
封装代码
javascript
/**
* 带有超时和重试功能的请求方法
* @param {string} url - 请求的URL
* @param {Object} options - fetch的配置选项
* @param {number} timeout - 超时时间(毫秒)
* @param {number} maxRetries - 最大重试次数
* @returns {Promise<Response>} - 返回fetch的响应
*/
function fetchWithRetry(url, options = {}, timeout = 5000, maxRetries = 3) {
return new Promise(async (resolve, reject) => {
let retries = 0;
// 发起请求
const attemptFetch = async () => {
try {
// 创建一个超时 Promise
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error("请求超时")), timeout);
});
// 发起 fetch 请求
const fetchPromise = fetch(url, options);
// 使用 Promise.race 实现超时控制
const response = await Promise.race([fetchPromise, timeoutPromise]);
// 如果响应状态码不是2xx,抛出错误
if (!response.ok) {
throw new Error(`请求失败,状态码: ${response.status}`);
}
// 请求成功,返回响应
resolve(response);
} catch (error) {
retries++;
console.warn(`请求失败,重试次数: ${retries}, 错误: ${error.message}`);
// 如果达到最大重试次数,抛出错误
if (retries >= maxRetries) {
reject(new Error(`请求失败,已达到最大重试次数: ${maxRetries}`));
} else {
// 否则,继续重试
attemptFetch();
}
}
};
// 开始第一次请求
attemptFetch();
});
}
// 使用示例
(async () => {
try {
const url = "https://jsonplaceholder.typicode.com/posts/1";
const response = await fetchWithRetry(url, {}, 2000, 3); // 超时2秒,最大重试3次
const data = await response.json();
console.log("请求成功:", data);
} catch (error) {
console.error("请求最终失败:", error.message);
}
})();
代码说明:
-
超时控制:
- 使用
Promise.race
实现超时功能。 - 如果
fetch
请求在指定时间内未完成,超时Promise
会先完成,从而中断请求。
- 使用
-
重试机制:
- 使用递归函数
attemptFetch
实现重试逻辑。 - 如果请求失败(超时或响应状态码非2xx),则重试,直到达到最大重试次数。
- 使用递归函数
-
错误处理:
- 如果请求失败,会记录错误并重试。
- 如果达到最大重试次数,抛出最终错误。
-
使用示例:
- 调用
fetchWithRetry
方法时,传入 URL、配置选项、超时时间和最大重试次数。 - 请求成功后,返回响应数据;失败后,抛出错误。
- 调用
示例输出:
-
如果请求成功:
css请求成功: { userId: 1, id: 1, title: "...", body: "..." }
-
如果请求失败:
makefile请求失败,重试次数: 1, 错误: 请求超时 请求失败,重试次数: 2, 错误: 请求超时 请求失败,重试次数: 3, 错误: 请求超时 请求最终失败: 请求失败,已达到最大重试次数: 3
注意事项:
-
浏览器兼容性:
fetch
和Promise
在现代浏览器中支持良好,但在旧版浏览器中可能需要 polyfill。- 如果需要兼容旧版浏览器,可以使用
axios
库替代fetch
。
-
重试间隔:
- 当前代码是立即重试。如果需要增加重试间隔,可以在重试前添加
await new Promise(resolve => setTimeout(resolve, delay))
。
- 当前代码是立即重试。如果需要增加重试间隔,可以在重试前添加
-
性能优化:
- 如果请求失败的原因是服务器过载,建议增加指数退避策略(Exponential Backoff)来避免加重服务器负担。
扩展:指数退避策略
如果需要实现指数退避策略(每次重试间隔时间逐渐增加),可以修改重试逻辑如下:
javascript
const delay = Math.pow(2, retries) * 1000; // 指数退避,例如 2s, 4s, 8s
await new Promise(resolve => setTimeout(resolve, delay));
attemptFetch();