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

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

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

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

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

考虑以下常见的代码模式,它在一个循环中顺序执行网络请求和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请求失败时,程序不应立即放弃,而是应该在限定的次数内进行多次尝试,直到请求成功或达到最大重试次数。这可以通过封装一个自定义的异步函数来实现。

立即学习“Java免费学习笔记(深入)”;

fetchWithRetry 函数详解

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

/** * 异步函数,用于带重试机制地获取网页内容并解析。 * @param {string} url - 要抓取的URL。 * @param {number} numberOfRetries - 最大重试次数。 * @returns {Promise} 解析后的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; // 达到最大重试次数后,抛出最终错误    }  }}

函数说明:

参数:url: 目标网页的URL。numberOfRetries: 允许的最大重试次数。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();

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

注意事项与最佳实践

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

总结

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

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1537875.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
构建健壮的Web抓取:JavaScript fetch请求的重试策略
上一篇 2025年12月21日 04:30:48
GrapesJS中阻止浏览器默认保存对话框弹出的方法
下一篇 2025年12月21日 04:31:02

相关推荐

  • 游戏服务器(Game Server)的后端架构

    游戏服务器的后端架构重要,因为它直接影响玩家的游戏体验。1) 高效的网络架构如使用tcp/ip和websocket处理客户端请求;2) 负载均衡通过nginx和haproxy分配流量;3) 数据同步使用分布式数据库如redis保证数据一致性;4) 安全性通过加密算法和验证机制防范攻击;5) 扩展性利…

    2026年8月27日
    000
  • 华为小艺AI竞赛Agent首战国际数学奥林匹克大赛(IMO)荣获佳绩!

    在2025年国际数学奥林匹克竞赛(imo)的特别邀请下,华为小艺ai竞赛agent首次登上这一全球最高水平的数学竞技舞台。经过为期三天的高强度比拼,该ai系统成功解出6道赛题中的5道,以总分34分的亮眼表现斩获银牌,仅以1分之差与金牌分数线(35分)擦肩而过。这一突破性成果,标志着华为在ai逻辑推理…

    2026年8月27日
    000
  • 带货新手快速入门 + AI 无人直播智能加持:轻松打造爆款直播间

    新手直播带货需先打好选品与定位基础,理解平台规则和“人货场”逻辑,再借助AI提升效率;AI可辅助内容生成、无人直播和短视频引流,但无法替代真人情感互动,应采用“人机协作”模式;通过OBS、TTS、虚拟数字人等工具实现AI直播,结合数据分析与用户思维持续优化,避免选品失误、内容单调、违规等问题,最终实…

    2026年8月27日
    000
  • 代码风格不一致?NextcloudCodingStandard帮你统一PHP代码风格

    在多人协作的 PHP 项目中,代码风格不一致是一个令人头疼的问题。不同的开发者可能有不同的编码习惯,导致代码可读性降低,维护成本增加。Nextcloud Coding Standard 旨在提供一套统一的代码风格规范,并结合 PHP CS Fixer 工具,可以自动格式化代码,解决代码风格不一致的问…

    用户投稿 2026年8月27日
    000
  • 歌尔股份:已在汽车电子相关传感器、光学零组件等领域取得一定进展

    ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜ 歌尔股份在2024年度业绩说明会上对公司未来发展战略进行了阐述。公司表示对AI智能眼镜市场前景充满信心,并将持续加大在AI智能眼镜整机及精密零组件的设计研发和生产制造方面的投入。 目前,歌尔股份…

    2026年8月27日
    100
  • 华硕X870/X870E主板惊艳亮相《影之刃零》试玩会

    华硕X870/X870E主板惊艳亮相《影之刃零》试玩会华硕X870/X870E主板惊艳亮相《影之刃零》试玩会华硕X870/X870E主板惊艳亮相《影之刃零》试玩会华硕X870/X870E主板惊艳亮相《影之刃零》试玩会

    7月26日至27日,国产武侠风格动作游戏《影之刃零》在北京首钢园举办了首次大型线下试玩活动,吸引了数千名玩家齐聚一堂,共赴这场“江湖论剑”。作为知名电竞品牌,rog玩家国度不仅为现场提供了大量高性能硬件支持,更重磅展出了两款备受关注的x870/x870e主板——兼具萌趣与性能的华硕rog x870 …

    2026年8月27日 用户投稿
    100
  • 在若依框架中如何找到和配置MyBatis依赖?

    在若依框架(ruoyi-vue)中配置和查找mybatis依赖是开发过程中常见的问题,尤其对于新手开发者。本文将详细说明如何在若依框架中找到并引入mybatis依赖。 在若依框架的项目结构中,MyBatis依赖通常是通过Maven管理的,具体会在项目的pom.xml文件中定义。根据提供的信息,我们可…

    2026年8月27日
    000
  • Laravel API中的错误处理和返回格式规范

    在 laravel 中实现错误处理和规范 api 返回格式的步骤包括:1) 使用 laravel 内置的异常处理机制捕获和处理异常;2) 定义统一的返回格式结构,包含 success、data 和 message 字段;3) 在关键业务逻辑中使用 try-catch 块处理特定异常;4) 利用 ap…

    2026年8月27日
    000
  • 流光号虚拟主播直播带货指南(附详细教程+配套工具资源)

    流光号虚拟主播直播带货是一种高效且具未来感的数字营销新范式,其核心在于通过定制化虚拟形象、精细化内容脚本、技术融合与数据迭代,实现24小时不间断、品牌高度一致的低成本运营,解决真人主播成本高、状态波动、时间受限等痛点,借助新奇感吸引流量,并通过智能互动与情感化内容提升转化率,最终依托数据分析持续优化…

    2026年8月27日
    300
  • 夸克AI写作怎么用_夸克AI文章生成功能使用教程

    夸克AI写作怎么用_夸克AI文章生成功能使用教程夸克AI写作怎么用_夸克AI文章生成功能使用教程夸克AI写作怎么用_夸克AI文章生成功能使用教程夸克AI写作怎么用_夸克AI文章生成功能使用教程

    夸克AI写作可通过浏览器快速生成高质量文章。首先打开夸克浏览器并登录账号,点击搜索框下方“AI”图标进入AI助手,选择“AI写作”功能;接着在界面中选定文章类型如说明文或小红书文案,并输入具体主题如“如何养护多肉植物”,可选设置目标读者与语气风格;然后设定文章长度为短篇、中篇或长篇,补充关键词如“多…

    2026年8月27日 用户投稿
    000
  • 告别传统API的烦恼:如何使用IbexaGraphQL打造高效灵活的数据接口

    可以通过一下地址学习composer:学习地址 传统API的困境与现代需求 作为一名开发者,你一定遇到过这样的场景:前端需要展示用户列表和每个用户的最新三篇文章,但后端提供的restful api却只有 /users 和 /posts 两个独立接口。于是,你不得不先请求 /users 获取用户id,…

    用户投稿 2026年8月27日
    000
  • 告别PHP阻塞等待:GuzzlePromises助你实现高效异步编程,优化复杂任务处理

    可以通过一下地址学习composer:学习地址 传统PHP的“等待之痛”:当你的应用被外部服务拖慢 想象一下,你正在构建一个php后台应用,其中一个核心功能是为用户生成一个聚合报告。这个报告的数据来源非常分散: 用户画像数据:来自内部的用户服务API。订单历史记录:来自另一个内部的订单服务API。实…

    用户投稿 2026年8月27日
    000
  • 我的世界神奇宝贝大师球获取攻略

    我的世界神奇宝贝大师球获取攻略我的世界神奇宝贝大师球获取攻略我的世界神奇宝贝大师球获取攻略我的世界神奇宝贝大师球获取攻略

    在我的世界神奇宝贝模组中,大师球是一种非常实用的道具,可以用来捕捉各种精灵小宠物,成功捕捉后便能将其驯服并为自己所用。那么,如何获得神奇宝贝大师球呢?这么实用的道具当然要多准备几个。大师球可以通过合成方式获取,需要制作多个部件,包括盖子和铁质结构部分,需要用到果实和铁锭等材料,同时还需要使用工作台和…

    2026年8月27日 用户投稿
    000
  • 幻彩号虚拟形象电商实战指南(附保姆级教程+工具资源库)

    幻彩号虚拟形象电商是将数字分身转化为商品的新兴商业模式。核心路径为:先定位虚拟形象风格与受众,再通过Vroid Studio、Blender等工具创建2D或3D模型,结合Live2D实现动态表现;随后生产短视频、直播等内容赋予形象“生命”,并通过B站、抖音、小红书等平台矩阵传播,结合NFT、虚拟商品…

    2026年8月27日
    400
  • Laravel与Livewire实现实时前端

    使用laravel和livewire实现实时前端可以通过以下步骤实现:1. 安装和配置livewire,使用composer安装并在视图中添加必要的样式和脚本;2. 创建livewire组件,使用命令行工具生成组件文件,并在其中定义属性和方法;3. 在laravel视图中使用livewire组件,实…

    2026年8月27日
    000
  • 海尔智家与法国大西洋集团达成空气能热泵合作协议

    7月18日,海尔智家与法国大西洋集团正式签订合作协议,开启双方在空气能热泵领域的深度合作。此次联手旨在共同推进绿色建筑高效、舒适、智能化解决方案的研发与落地,助力低碳可持续发展。 根据协议内容,双方将聚焦研发符合新《含氟气体法规》要求的家用一体式R290空气能热泵及家用分体式空气能热泵。依托海尔智家…

    2026年8月27日
    100
  • Laravel Telescope调试工具安装和使用

    laravel telescope的安装与使用步骤如下:1. 运行composer require laravel/telescope,2. 执行php artisan telescope:install,3. 发布配置文件php artisan vendor:publish –prov…

    2026年8月27日
    100
  • 美图秀秀如何去除图片上的文字_美图秀秀文字去除技巧

    1、使用消除笔可智能填充文字区域,通过涂抹目标位置并自动匹配周围纹理实现去字;2、克隆图章工具需手动采样并复制空白区域覆盖文字,适合复杂背景;3、裁剪功能适用于边缘文字,通过调整画面范围直接删除含字部分;4、贴纸或滤镜可用于遮盖残留文字,提升整体视觉效果。 如果您在使用美图秀秀处理图片时,希望去掉图…

    2026年8月27日
    100
  • 如何优雅地管理PHP异步操作:使用Composer引入GuzzleHttp/Promises

    Composer在线学习地址:学习地址 告别“回调地狱”:PHP异步操作的痛点 你是否曾遇到这样的场景:你的php应用需要从多个外部服务获取数据,或者执行一些耗时的后台任务。如果这些操作都是同步进行的,那么用户就得眼睁睁地看着页面转圈,直到所有操作完成。这不仅严重影响了用户体验,也浪费了服务器资源。…

    用户投稿 2026年8月27日
    000
  • Java、Python和C 三者的区别是什么?

    探讨Java、Python和C三者的差异 在编程世界中,Java、Python和C是三种备受欢迎的编程语言。每种语言都有其独特的特征和适用领域,了解它们的差异对于选择合适的编程工具至关重要。 语言特性 Java 类型:Java属于静态类型语言,变量类型在编译时已确定。运行环境:Java程序运行于Ja…

    2026年8月27日
    100

发表回复

登录后才能评论
关注微信