J*aScript中Fetch请求的健壮性:实现自动重试机制处理网络不稳定


JavaScript中Fetch请求的健壮性:实现自动重试机制处理网络不稳定

本文旨在解决在j*ascript中进行大量网络请求时,因网络不稳定导致进程中断的问题。通过引入一个自定义的`fetchwithretry`函数,文章详细阐述了如何构建一个具备自动重试功能的请求机制。该机制能在请求失败时自动进行多次尝试,显著提升了web抓取或api调用的健壮性和成功率,确保即使面对瞬时网络故障也能顺利完成任务。

引言:网络请求的挑战与健壮性需求

在进行Web数据抓取、API调用或任何涉及大量HTTP请求的J*aScript应用中,网络的不稳定性是一个常见且难以避免的挑战。当应用程序需要在一个循环中发送成百上千个请求时,即使是短暂的网络波动、服务器响应延迟或瞬时连接中断,都可能导致整个处理流程中断,影响数据的完整性和程序的稳定性。

考虑以下常见的代码模式,它在一个循环中顺序执行网络请求和DOM解析:

for (const el of NodeList) {
  const url = el.getAttribute('href');
  // 如果此处fetch请求失败或没有响应,后续代码将不会执行
  const res = await fetch(url); 
  const html = await res.text();
  const parser = new DOMParser();
  const doc = parser.parseFromString(html, 'text/html');
  alert('parsed successfully'); // 仅在浏览器环境中有效
}

在这种模式下,一旦fetch(url)操作因为网络问题抛出错误或长时间无响应,后续的代码(如res.text()、DOMParser解析)将无法执行,导致当前循环迭代中断,甚至可能影响到整个循环的继续执行,从而破坏整个数据获取过程。为了提升应用的鲁棒性,我们需要一种机制来优雅地处理这些瞬时故障。

解决方案:实现请求重试机制

解决上述问题的核心在于引入一个重试机制。当fetch请求失败时,程序不应立即放弃,而是应该在限定的次数内进行多次尝试,直到请求成功或达到最大重试次数。这可以通过封装一个自定义的异步函数来实现。

fetchWithRetry 函数详解

我们将创建一个名为fetchWithRetry的异步函数,它负责处理单个URL的请求,并在失败时自动重试。

LALAL.AI LALAL.AI

AI人声去除器和声乐提取工具

LALAL.AI 196 查看详情 LALAL.AI
/**
 * 异步函数,用于带重试机制地获取网页内容并解析。
 * @param {string} url - 要抓取的URL。
 * @param {number} numberOfRetries - 最大重试次数。
 * @returns {Promise<Document>} 解析后的DOM Document对象。
 * @throws {Error} 当达到最大重试次数后仍然失败时抛出错误。
 */
async function fetchWithRetry(url, numberOfRetries) {
  try {
    // 尝试执行标准的fetch请求
    const response = await fetch(url);

    // 检查HTTP响应状态码,例如,非2xx状态码也可能需要重试
    if (!response.ok) {
        // 对于服务器错误(5xx)或特定客户端错误(如429 Too Many Requests)可以考虑重试
        // 对于其他如404 Not Found,通常不适合重试
        if (numberOfRetries > 0 && (response.status >= 500 || response.status === 429)) {
            console.warn(`URL: ${url} 收到非成功状态码 ${response.status}。正在重试... 剩余重试次数: ${numberOfRetries}`);
            // 可以添加一个延迟,避免立即重试导致服务器压力过大或再次失败
            await new Promise(resolve => setTimeout(resolve, 1000 * (3 - numberOfRetries + 1))); // 递增延迟
            return fetchWithRetry(url, numberOfRetries - 1);
        } else {
            // 对于不适合重试的非成功状态码,直接抛出错误
            throw new Error(`HTTP Error: ${response.status} for URL: ${url}`);
        }
    }

    const html = await response.text();
    const parser = new DOMParser(); // 注意:DOMParser是浏览器API,在Node.js中需要polyfill
    const doc = parser.parseFromString(html, 'text/html');
    console.log(`URL: ${url} 解析成功。`);
    return doc;
  } catch (error) {
    // 捕获网络错误或其他运行时错误
    if (numberOfRetries > 0) {
      console.error(`URL: ${url} 请求失败。正在重试... 剩余重试次数: ${numberOfRetries}`, error);
      // 在重试前添加一个延迟,给网络或服务器恢复时间
      await new Promise(resolve => setTimeout(resolve, 1000 * (3 - numberOfRetries + 1))); // 递增延迟
      return fetchWithRetry(url, numberOfRetries - 1); // 递归调用自身进行重试
    } else {
      console.error(`URL: ${url} 请求失败。已达到最大重试次数。`, error);
      throw error; // 达到最大重试次数后,抛出最终错误
    }
  }
}

函数说明:

  1. 参数:
    • url: 目标网页的URL。
    • numberOfRetries: 允许的最大重试次数。
  2. try...catch 块:
    • try 块: 包含正常的fetch请求、响应处理和DOMParser解析逻辑。如果请求成功且响应状态码为2xx,则返回解析后的Document对象。
    • 响应状态码检查: 除了网络错误,我们还增加了对HTTP响应状态码的检查。对于服务器错误(5xx)或特定的客户端错误(如429 Too Many Requests,表示请求过于频繁),也视为需要重试的情况。对于其他如404(未找到)等,通常不应重试,而是直接抛出错误。
    • catch 块: 捕获任何在try块中发生的错误,包括网络连接问题、DNS解析失败或上述非成功的HTTP响应。
      • 重试判断: 检查numberOfRetries是否大于0。如果还有剩余重试次数,则输出错误信息,并递归调用fetchWithRetry函数,同时将numberOfRetries减1。
      • 延迟重试: 在每次重试前,我们引入了一个setTimeout来创建一个延迟。这非常重要,可以避免在短时间内对服务器造成过大压力,并给网络或服务器一个恢复的时间。这里使用了一个简单的递增延迟策略,例如第一次重试等待1秒,第二次等待2秒,以此类推。
      • 最大重试次数: 如果numberOfRetries为0,表示已达到最大重试次数,此时不再重试,而是抛出原始错误,让上层调用者处理。

在循环中集成重试函数

现在,我们可以将原始循环中的fetch调用替换为我们新创建的fetchWithRetry函数:

const NodeList = [
  { getAttribute: (attr) => attr === 'href' ? 'https://example.com/page1' : '' },
  { getAttribute: (attr) => attr === 'href' ? 'https://example.com/page2' : '' },
  { getAttribute: (attr) => attr === 'href' ? 'https://example.com/page3' : '' },
  // 更多节点...
];

async function processNodes() {
  for (const el of NodeList) {
    const url = el.getAttribute('href');
    try {
      // 调用带重试机制的函数,例如,最多重试3次
      const doc = await fetchWithRetry(url, 3); 
      // 在此处处理解析后的文档对象
      console.log(`成功处理URL: ${url},文档标题: ${doc.title}`);
      // alert('parsed successfully'); // 在实际应用中,避免在循环中频繁使用alert
    } catch (error) {
      console.error(`处理URL: ${url} 最终失败:`, error.message);
      // 可以选择记录失败的URL,或进行其他错误恢复操作
    }
  }
  console.log('所有节点处理完毕。');
}

// 调用主处理函数
processNodes();

通过这种方式,即使在处理过程中遇到临时的网络问题,程序也能自动尝试恢复,大大提高了整个数据获取过程的健壮性。

注意事项与最佳实践

  1. 最大重试次数的设定: 合理设置numberOfRetries至关重要。过多的重试可能导致不必要的资源消耗和时间延长,而过少的重试则可能无法应对常见的瞬时故障。通常,3到5次是一个比较合理的范围。
  2. 重试延迟策略:
    • 固定延迟: 每次重试都等待相同的时间。
    • 指数退避(Exponential Backoff): 每次重试的等待时间逐渐增加(例如,1秒、2秒、4秒、8秒...)。这种策略能有效避免在服务器负载过高时进一步加剧问题,并给服务器更长的恢复时间。上述示例中采用了简化的递增延迟。
    • 抖动(Jitter): 在指数退避的基础上,随机化一部分延迟时间,避免所有客户端同时重试造成“惊群效应”。
  3. 错误类型区分: 并非所有错误都适合重试。例如:
    • 网络错误(Network Error)、超时(Timeout): 适合重试。
    • HTTP 5xx 状态码(服务器错误): 通常适合重试。
    • HTTP 429 Too Many Requests: 适合重试,但需要结合指数退避和等待Retry-After头部字段指示的时间。
    • HTTP 4xx 状态码(客户端错误,如404 Not Found、400 Bad Request): 通常不适合重试,因为这意味着请求本身有问题,重试也无济于事。
  4. 超时配置: fetch API本身支持AbortController来实现请求超时。将其与重试机制结合,可以在规定时间内未收到响应时触发重试。
  5. 错误日志与监控: 详细的错误日志对于调试和理解系统行为至关重要。记录每次失败的URL、错误类型和重试次数,有助于发现潜在的长期问题。
  6. 并发控制: 如果在循环中并行发送大量请求,还需要考虑并发控制,避免同时打开过多的网络连接,这可以通过使用Promise.allSettled结合限制并发数的工具库(如p-limit)来实现。
  7. DOMParser的适用性: DOMParser是浏览器环境下的API。如果在Node.js环境中进行服务器端抓取,需要使用类似jsdom或cheerio等库来解析HTML。本教程的示例代码假设在浏览器或类似浏览器环境(如Electron)中运行。

总结

通过实现一个健壮的fetchWithRetry函数,我们可以显著提升J*aScript应用程序处理网络请求的可靠性。这种重试机制能够有效地应对瞬时网络故障和服务器不稳定,确保即使在复杂的网络环境下,也能最大限度地完成数据获取任务。结合合理的重试策略、延迟机制和错误处理,我们可以构建出更加稳定和用户友好的Web应用。

以上就是J*aScript中Fetch请求的健壮性:实现自动重试机制处理网络不稳定的详细内容,更多请关注其它相关文章!


# 也能  # 房地产网站推广运营  # seo网站管理员招聘  # 基础技术seo推广  # 厦门seo排名优化方式  # 网站建设获客电话  # 枣庄如何优化网站  # 价值营销推广文案范例  # 网站营销与推广方式  # 房地产尾盘营销推广方案  # 嘉兴百度网站关键词排名  # 来实现  # 是一个  # 不适合  # 客户端  # 我们可以  # javascript  # 不稳定  # 抛出  # 递归  # 重试  # api调用  # 状态码  # dns  # ai  # 工具  # 浏览器  # node  # node.js  # js  # html  # java 


相关栏目: 【 Google疑问12 】 【 Facebook疑问10 】 【 优化推广96088 】 【 技术知识133117 】 【 IDC资讯59369 】 【 网络运营7196 】 【 IT资讯61894


相关推荐: 《崩坏:星穹铁道》3.6版本异相仲裁打法及配队推荐  Win10共享文件夹设置方法 Win10局域网文件共享全攻略【教程】  百度小说看书时如何翻页_百度小说手动翻页与自动翻页设置  泰拉瑞亚水晶无法放置问题  高效调试PHP大型嵌套数组:JSON序列化与可视化工具实践  《豆瓣》私信用户方法  J*aScript:从子元素中批量移除特定CSS类  解决C#跨线程访问XML对象的异常 安全的并发XML处理模式  电脑双系统如何安装和卸载 Windows和Linux双系统安装教程【详解】  mysql镜像配置如何恢复数据_mysql镜像配置数据恢复详细流程  微信朋友圈怎么设置三天可见 微信朋友圈设置指定天数可见步骤【教程】  优化Flask模板中SQLAlchemy查询迭代标签:处理字符串空格问题  风神瞳获取全攻略  优酷下载视频的清晰度怎么选_优酷缓存清晰度设置与选择指南  QQ邮箱官方登录页_腾讯出品安全稳定的邮箱服务  Win10显卡驱动安装失败怎么办 Win10使用DDU彻底卸载驱动【解决】  鸿蒙单条备忘录如何加密  《真我》申请退款方法  阿里云共享相册入口在哪  b站如何剪辑视频_b站必剪app使用教程  向日葵客户端怎么进行语音通话_向日葵客户端语音通话功能使用方法  智学网app怎么登录忘记密码_智学网app忘记密码找回与重新登录操作方法  铁路12306怎么申请退票_铁路12306退票申请操作流程  word怎么将图片设置为页面背景并不影响打印_Word图片背景设置方法  使用Google服务账号实现Google Drive API无缝集成与文件访问  CSS动画如何实现图标旋转并放大_transform rotate scale @keyframes实现  iPhone 13 Pro Max如何设置桌面小组件_iPhone 13 Pro Max小组件添加指南  《顺丰同城骑士》查看我的技能方法  J*aScript与HTML元素交互:图片点击事件与链接处理教程  windows10怎么开启卓越性能_windows10电源选项代码激活  Google Drive API 认证:服务账户与OAuth 2.0的选择与实践  《东方财富》条件单关闭方法  解决异步Python机器人中同步操作的阻塞问题  windows10怎么关闭自动安装应用_windows10禁止推广应用下载  火柴人战争网页版在线玩  使用逻辑应用(Logic Apps)自动处理邮件附件中的XML到Excel  vivo浏览器怎么离线保存网页 vivo浏览器下载完整页面以便无网络时阅读  创客贴登录页面入口 创客贴网页版最新网址链接  TikTok视频播放中断怎么办 TikTok播放异常修复方法  荣耀Magic7拍照夜景噪点处理_荣耀Magic7相机优化  Lar*el Dusk 测试中管理浏览器权限:以剪贴板访问为例  在PySimpleGUI中实现键盘按键绑定按钮事件  如何在CSS中实现盒模型多列间距_grid-gap与padding结合  第五人格PC版怎么避免被封号_第五人格PC版防封号注意事项  J*a里如何处理ArithmeticException并防止除零_算术异常防护策略解析  优化 React onClick 事件处理:函数引用与箭头函数的对比  微信客户端怎么查看二维码_微信客户端个人二维码查看方法  漫蛙漫画官方版直通入口 2025漫蛙漫画免注册访问说明  百度网盘如何设置上传限额  PHP 4 函数中引用参数的默认值限制与解决方案 

 2025-11-10

了解您产品搜索量及市场趋势,制定营销计划

同行竞争及网站分析保障您的广告效果

点击免费数据支持

提交您的需求,1小时内享受我们的专业解答。

运城市盐湖区信雨科技有限公司


运城市盐湖区信雨科技有限公司

运城市盐湖区信雨科技有限公司是一家深耕海外推广领域十年的专业服务商,作为谷歌推广与Facebook广告全球合作伙伴,聚焦外贸企业出海痛点,以数字化营销为核心,提供一站式海外营销解决方案。公司凭借十年行业沉淀与平台官方资源加持,打破传统外贸获客壁垒,助力企业高效开拓全球市场,成为中小企业出海的可靠合作伙伴。

 8156699

 13765294890

 8156699@qq.com

Notice

We and selected third parties use cookies or similar technologies for technical purposes and, with your consent, for other purposes as specified in the cookie policy.
You can consent to the use of such technologies by closing this notice, by interacting with any link or button outside of this notice or by continuing to browse otherwise.