前端【免费下载链接】urqlThe highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.项目地址https://gitcode.com/gh_mirrors/ur/urql点击查看免费下载本文基于 urql 官方文档的 Retrying Operations 章节docs/advanced/retry-operations.md结合urql/exchange-retry的源码实现exchanges/retry/src/retryExchange.ts与官方示例examples/with-retry系统讲解retryExchange的安装配置、重试参数语义、错误条件判定与客户端故障转移failover方案。读完本文你将能够为 urql Client 接入带指数退避exponential backoff的重试能力并针对网络错误与 GraphQL 错误分别定制重试策略。为什么需要 retryExchangeurql 的客户端由一条 exchange 链组成操作Operation依次流经cacheExchange、fetchExchange等最终向 GraphQL 端点发起请求可参见 docs/architecture.md。真实网络环境并不稳定瞬时断网、超时、服务端 5xx 都可能让一个本可以成功的请求失败。urql/exchange-retry提供的retryExchange正是为解决这类问题而生当某个操作失败后它会在等待一段可配置的延迟后重新把该操作推回 exchange 链让请求再试一次。默认情况下它只重试网络错误但你也可以通过选项扩展它的行为——例如重试带特定graphQLErrors的响应、限制最大尝试次数、甚至把请求切换到备用端点。仓库为该功能提供了可直接运行的示例examples/with-retry它连接trygql.formidable.dev/graphql/intermittent-colors这个会随机抛出NO_SOUP错误的服务端 schema直观展示重试的实际效果。安装与接入 Client先安装依赖包发布名为urql/exchange-retry源码位于 exchanges/retryyarn add urql/exchange-retry # 或 npm install --save urql/exchange-retry然后在创建Client时通过exchanges数组把retryExchange接入import { Client, cacheExchange, fetchExchange } from urql; import { retryExchange } from urql/exchange-retry; // 以下均为默认值可全部省略 const options { initialDelayMs: 1000, // 首次重试前等待 1 秒 maxDelayMs: 15000, // 重试间隔上限 15 秒 randomDelay: true, // 启用随机指数退避 maxNumberAttempts: 2, // 总尝试次数含首次请求即最多重试 1 次 retryIf: err err err.networkError, // 只在网络错误时重试 }; const client new Client({ url: http://localhost:1234/graphql, exchanges: [ cacheExchange, retryExchange(options), // 通过工厂函数创建 exchange 实例 fetchExchange, ], });在 exchange 链中的位置retryExchange必须放在fetchExchange之前、cacheExchange之后。原因有二放在fetchExchange之前重试只会在操作已尝试过真实网络请求并失败后才触发而不是在缓存层就无意义地重复执行放在cacheExchange之后重试的请求仍会正常流经缓存层命中缓存的结果不会重复发起网络请求。从实现看exchanges/retry/src/retryExchange.tsretryExchange将原始操作流与内部重试流merge后一起forward给下游 exchange并在结果流上用filter拦截失败结果——失败的响应被截住并重新注入重试流而成功结果或已耗尽重试次数的失败结果则放行给调用方。注意示例 examples/with-retry/src/App.jsx 为了演示纯重试行为直接使用了retryExchangefetchExchange的组合未接入 cache。实际项目中仍建议按上文顺序放置cacheExchange。参数详解退避策略与尝试次数retryExchange接受一个可选的RetryExchangeOptions配置对象其类型定义与 TSDoc 注释位于 exchanges/retry/src/retryExchange.ts。各参数说明如下参数默认值说明initialDelayMs1000首次重试的最小等待时长毫秒。例如设为1000则操作失败后先等 1 秒再重试。maxDelayMs15000任意两次重试之间延迟的上限毫秒防止退避时间无限增长而让请求迟迟不发。randomDelaytrue是否启用随机指数退避。false时每次重试间隔严格按initialDelayMs线性递增。maxNumberAttempts2最大尝试次数包含首次请求。2表示首次失败后最多再重试 1 次传入Number.POSITIVE_INFINITY可无限重试。retryIf仅网络错误(error, operation) boolean自定义是否重试该次失败。retryWith—(error, operation) Operation \| null \| undefined返回一个新Operation替换失败的操作用以重试返回空值则不重试。retryIf存在时优先于retryWith。延迟如何增长源码级解读从 exchanges/retry/src/retryExchange.ts 可以看出退避算法的实际逻辑随机退避randomDelay: true每次重试的延迟 当前延迟 ×(Math.random() 1.5)即每次在前一次基础上放大 1.52.5 倍一旦放大后的值达到maxDelayMs则直接封顶为maxDelayMs。这个随机的抖动因子用于缓解惊群效应thundering herd problem——如果大量客户端在同一时刻失败又用完全相同的时间片重试会形成对服务器的请求洪峰随机化让重试请求在时间上错开。固定递增randomDelay: false第 N 次重试的延迟 N × initialDelayMs同样受maxDelayMs封顶。例如initialDelayMs: 1000时首次失败等 1 秒、再次失败等 2 秒以此类推。这一点与文档描述一致并由测试用例 exchanges/retry/src/retryExchange.test.ts 直接验证固定延迟模式下第 i 次调用前恰好推进了i × initialDelayMs毫秒。尝试次数如何判定源码中MAX_ATTEMPTS options.maxNumberAttempts || 2exchanges/retry/src/retryExchange.ts且每次重试计数通过operation.context.retry.count累加当retry.count MAX_ATTEMPTS - 1时判定次数耗尽不再重试exchanges/retry/src/retryExchange.ts。因此maxNumberAttempts: 2的实际含义是「首次请求 最多 1 次重试」测试用例也确认了response即下游 fetch被调用的总次数等于maxNumberAttemptsexchanges/retry/src/retryExchange.test.ts。另外两点实现细节值得注意同一操作成功后retry状态计数与延迟会被重置exchanges/retry/src/retryExchange.ts测试 exchanges/retry/src/retryExchange.test.ts 验证了「先失败、后成功」的场景下计数归零若某个操作在重试等待期间收到teardown 事件例如查询组件卸载触发重试会被takeUntil终止避免对已无人关心的操作做无谓重试exchanges/retry/src/retryExchange.ts。按错误类型定制重试retryIfretryExchange默认只在结果带networkError时重试见默认值retryIf: err err err.networkError。urql 的CombinedError同时持有networkError与graphQLErrors两类信息定义见 packages/core/src/utils/error.ts因此你可以用retryIf按错误类型精细控制import { Client, cacheExchange, fetchExchange } from urql; import { retryExchange } from urql/exchange-retry; const client new Client({ url: http://localhost:1234/graphql, exchanges: [ cacheExchange, retryExchange({ retryIf: error { // 出现任意 GraphQL 错误或网络错误都触发重试 return !!(error.graphQLErrors.length 0 || error.networkError); }, }), fetchExchange, ], });retryIf收到的第一个参数是CombinedError第二个参数是失败的Operation——你甚至可以根据操作类型query / mutation / subscription或操作上下文做更细的区分。例如只对查询重试、而对变更保持不重试是retryExchangeTSDoc 中明确提到的典型用法exchanges/retry/src/retryExchange.ts。针对特定错误码重试若只想重试特定错误码可像官方示例那样读取extensions.codeexamples/with-retry/src/App.jsxretryExchange({ maxNumberAttempts: 10, maxDelayMs: 500, retryIf: error { // 示例 schema 会随机抛出 code 为 NO_SOUP 的错误 return ( error.graphQLErrors.some(x x.extensions?.code NO_SOUP) || !!error.networkError ); }, }),结合该示例的Color.jsxexamples/with-retry/src/Color.jsx你还可以通过result.operation.context.retryCount得知这次查询实际重试了多少次方便在 UI 上提示用户。注意示例里maxNumberAttempts: 10表示最多重试 9 次配合maxDelayMs: 500让退避封顶在半秒内演示体验更流畅。故障转移retryWith 与备用端点当网络故障导致当前端点不可用例如某部分基础设施宕机但还存在一个可用的备用 GraphQL 端点比如不同域名、不同服务商时retryWith可以在客户端直接实现故障转移failover / fallback。它同样适用于 GraphQL 错误场景例如 API 按滚动窗口策略部署——新版在 URL X、旧版仍保留在 URL Y旧版报错时自动切换到新版。const fallbackUrl http://localhost:1337/anotherGraphql; const options { initialDelayMs: 1000, maxDelayMs: 15000, randomDelay: true, maxNumberAttempts: 2, retryWith: (error, operation) { if (error.networkError) { // 把 operation 的 context.url 换成备用端点并返回新 operation const context { ...operation.context, url: fallbackUrl }; return { ...operation, context }; } return null; // 其他错误不重试 }, };retryWith的本质是「把失败的Operation替换成一个新Operation再重试」返回Operation则重试该新操作返回null/undefined则不重试exchanges/retry/src/retryExchange.ts。它在功能上可以替代retryIf的「是否重试」判断返回真值即重试、返回空值即放弃但当两者同时配置时retryIf优先见 API 文档 docs/api/retry-exchange.md 与源码注释 exchanges/retry/src/retryExchange.ts。测试用例 exchanges/retry/src/retryExchange.test.ts 展示了retryWith的两种形态返回null时forward只被调用 1 次即不重试exchanges/retry/src/retryExchange.test.ts返回新操作时新操作会携带你注入的context例如递增的counter下游 fetch 依次收到这些带标记的操作。需要说明的两点限制第一retryWith只做端点切换不做请求负载均衡——它不会把请求分摊到多个端点更细粒度的分流需要按你的业务场景自行扩展第二切换端点后仍然遵循maxNumberAttempts等重试次数约束。调试与观察重试行为retryExchange在重试过程中会通过dispatchDebug发出调试事件exchanges/retry/src/retryExchange.tsretryAttempt操作失败、即将重试事件消息中带(retryCount / MAX_ATTEMPTS)形式的重试进度data里包含retryCount与delayAmountretryExhausted达到最大重试次数、停止重试exchanges/retry/src/retryExchange.ts。这些事件可以被 urql Devtools 或自定义调试 exchange 捕获用于在生产环境观测重试频率与退避时长判断参数是否合理例如maxDelayMs是否过小导致退避封顶过早、maxNumberAttempts是否过大导致无效请求堆积。参考高级指南原文docs/advanced/retry-operations.mdAPI 文档docs/api/retry-exchange.md源码实现exchanges/retry/src/retryExchange.ts测试用例exchanges/retry/src/retryExchange.test.ts可运行示例examples/with-retry赞分享前端【免费下载链接】urqlThe highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.项目地址https://gitcode.com/gh_mirrors/ur/urql点击查看免费下载相关推荐urql retryExchange 完全指南urql/exchange-retry 的重试策略、指数退避与故障转移实践urql retryExchange 完全指南urql/exchange retry 的重试策略、指数退避与故障转移实践 本文是 urql GraphQL前端3分钟快速部署高性能分布式IM系统悟空IM终极实践指南 3分钟快速部署高性能分布式IM系统悟空IM终极实践指南 悟空IMWuKongIM是一款开源的高性能分布式通信基础设施专为即时通讯、实时交互和消息中前端urql重试机制实现基于retryExchange的网络错误自动恢复方案urql重试机制实现基于retryExchange的网络错误自动恢复方案 在现代Web应用开发中网络请求的稳定性直接影响用户体验。当用户在弱网环境下操作或服前端上一篇MinerU对比分析与其他PDF转换工具的全面对比下一篇微信聊天记录永久保存指南用WeChatMsg打造你的数字记忆保险箱创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
PaddleSpeech 说话人验证实战:VoxCeleb 上 ECAPA-TDNN 的 EER 结果与 S-Norm 评分详解 人工智能语音音频NLP媒体生成 【免费下载链接】PaddleSpeech Easy-to-use Speech Toolkit including Self-Supervised Learning model, SOTA/Streaming ASR with punctuation, Streaming TTS with text frontend, Speaker Verification System, End-to-End Speech Translation … · 2026/9/25 2:44:20
CSM331A实现低成本CAN扩展的工程实践 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 3:51:24
OneAPI计费系统1.2.0:部署、计费与避坑指南 简介:一款面向开发者及站长的一站式接口计费管理系统开源版,支持对接多种接口并灵活配置免费、资源包、混合计费模式,适用于需要为API服务搭建自动计费与用户体系的场景。新版修复若干已知缺陷,优化特定金额扣费逻辑,增… · 2026/9/25 3:51:24
面向 AI Agent 的文档编写方法论:OpenChamber writing-for-agents 技能解析 AI Agent人工智能代码智能体交互助手 【免费下载链接】openchamber Agentic Development Environment based on OpenCode AI agent 项目地址: https://gitcode.com/gh_mirrors/op/openchamber 点击查看 免费下载 本文以 OpenChamber 仓库中 .agents/skills/writing… · 2026/9/25 3:51:17
不花一分钱,用树莓派+ffmpeg+夸克网盘搭建家用监控录像系统 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 3:51:11
实验室认可中投诉处理程序如何从摆设变利器 1. 为什么投诉处理程序会在实验室认可里翻车?先说个我见过很多次的场景:实验室花了三个月把体系文件写得漂漂亮亮,内审管评都做完了,上报CNAS/CMA评审材料的时候一切正常。结果现场评审当天,评审员翻到投诉处理程序&am… · 2026/9/25 3:51:05
深入理解itk::Image:医学图像处理核心数据结构与几何变换 1. 为什么说 itk::Image 是医学图像处理的地基做医学影像处理的人,几乎天天和 ITK 打交道。无论是 DICOM 转 NIfTI、图像配准、分割还是三维重建,底层的数据结构几乎都是 itk::Image。我最早接触 ITK 时,第一反应是“这不就是一个带维度的数组… · 2026/9/25 3:50:59
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37