Apollo Client ErrorLink 完全指南基于apollo/client/link/error的 GraphQL 错误处理实战【免费下载链接】apollo-clientThe industry-leading GraphQL client for TypeScript, JavaScript, React, Vue, Angular, and more. Apollo Client delivers powerful caching, intuitive APIs, and comprehensive developer tools to accelerate your app development.项目地址: https://gitcode.com/gh_mirrors/ap/apollo-client本篇技术指南围绕仓库公开 API 报告 .api-reports/api-report-link_error.api.md 所声明的apollo/client/link/error模块展开系统讲解 Apollo Client 官方推荐的ErrorLink类及其配套类型ErrorHandler、ErrorHandlerOptions并深入源码 src/link/error/index.ts 与测试 src/link/error/tests/index.ts说明其触发时机、错误分类、重试与忽略机制。读完本文你将能够用ErrorLink统一捕获 GraphQL 错误、协议错误与网络错误实现日志、上报、重试与错误静默等常见需求。ErrorLink 是什么面向响应的错误处理链在 Apollo Client 的 link 链中请求从上游流向终止 link如 HttpLink而响应则沿链路反向回传。ErrorLink是一个特殊的 link它不拦截请求本身而是在GraphQL 操作执行完毕、结果沿链路回传时触发你注册的errorHandler回调用于检查并处理出现的错误。因此它非常适合放在所有终止 link 之前即concat链的靠前位置这样任何下游 linkHTTP、WS、批处理等产生的错误都能被它观察到。该模块的公开 API 由 API Extractor 报告完整定义为以下三部分见 .api-reports/api-report-link_error.api.md// public (undocumented) export namespace ErrorLink { export interface ErrorHandler { (options: ErrorHandlerOptions): ObservableApolloLink.Result | void; } export interface ErrorHandlerOptions { error: ErrorLike; forward: ApolloLink.ForwardFunction; operation: ApolloLink.Operation; result?: ApolloLink.Result; } export namespace ErrorLinkDocumentationTypes { ... } } // public export class ErrorLink extends ApolloLink { constructor(errorHandler: ErrorLink.ErrorHandler); } // public deprecated (undocumented) export function onError(errorHandler: ErrorLink.ErrorHandler): ErrorLink;其中ErrorLink是推荐使用的类onError是旧版本遗留的工厂函数已被标记为deprecated详见下文迁移说明。快速上手接入 ErrorLink模块入口在apollo/client/link/error对应源码文件为 src/link/error/index.ts。引入方式import { ErrorLink } from apollo/client/link/error; import { ApolloLink } from apollo/client/link; const errorLink new ErrorLink(({ operation, error }) { // 在这里统一处理三类错误GraphQL 错误、协议错误、网络错误 console.error(${operation.operationName} 执行失败:, error); }); const client new ApolloClient({ link: ApolloLink.from([errorLink, httpLink]), cache: new InMemoryCache(), });构造函数签名如下与 API 报告一致constructor(errorHandler: ErrorLink.ErrorHandler): ErrorLinkerrorHandler的唯一约束是回调的返回值要么是void仅观察、不干预要么是一个ObservableApolloLink.Result用于重试操作。测试 src/link/error/tests/index.ts 中大量使用了new ErrorLink(callback)jest.fn()的断言方式验证回调入参。ErrorHandlerOptions 详解回调能拿到什么ErrorHandler回调的唯一入参是一个ErrorHandlerOptions对象包含四个字段语义均可在 src/link/error/index.ts 的类型注释中找到字段类型说明errorErrorLike本次触发的错误对象。可能是CombinedGraphQLErrorsGraphQL 错误、CombinedProtocolErrors传输层协议错误或其他网络错误类型需要用各自的is()方法判别result?ApolloLink.Result服务器返回的原始 GraphQL 结果若可得可能包含部分数据data连同错误operationApolloLink.Operation产生错误的 GraphQL 操作详情含query、operationName、variables等forwardApolloLink.ForwardFunction指向 link 链中下一个 link 的函数。只有想重试操作时才需要调用forward(operation)它会返回一个新的 Observable 供上游订阅一个典型的日志用例源码 src/link/error/index.ts 的example代码块直接可运行import { ErrorLink } from apollo/client/link/error; import { CombinedGraphQLErrors, CombinedProtocolErrors, } from apollo/client/errors; const errorLink new ErrorLink(({ error, operation }) { if (CombinedGraphQLErrors.is(error)) { error.errors.forEach(({ message, locations, path }) console.log( [GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path} ) ); } else if (CombinedProtocolErrors.is(error)) { error.errors.forEach(({ message, extensions }) console.log( [Protocol error]: Message: ${message}, Extensions: ${JSON.stringify( extensions )} ) ); } else { console.error([Network error]: ${error}); } });触发时机与三类错误判别从 src/link/error/index.ts 的实现可见ErrorLink是在forward(operation)返回的 Observable 上订阅并按以下优先级判定GraphQL 错误result.errors非空将error包装为new CombinedGraphQLErrors(result, errors)传给回调。CombinedGraphQLErrors定义于 src/errors/CombinedGraphQLErrors.ts实例携带errors原始错误数组、data部分数据与extensions属性默认把各条message用换行符拼接为message。协议错误extensions[PROTOCOL_ERRORS_SYMBOL]存在对于 multipart 订阅等场景传输层错误被存放于extensions的私有 Symbol 键上见 src/errors/index.ts 中的PROTOCOL_ERRORS_SYMBOL与graphQLResultHasProtocolErrors此时error为CombinedProtocolErrors实例定义见 src/errors/CombinedProtocolErrors.ts。这类错误表示订阅传输本身的问题而非业务 GraphQL 错误。网络/其他错误Observableerror事件或同步抛出错误会经toErrorLike规范化。toErrorLikesrc/errors/index.ts的规则是已是ErrorLike则原样返回字符串包装为Error其他非常规类型Symbol、普通对象、数组等包装为UnconventionalError。测试中的 wraps strings emitted from terminating link in Error 与 wraps unconventional error types in UnconventionalError 用例即验证了这一点。因此error字段的类型判别建议如下if (CombinedGraphQLErrors.is(error)) { // 服务端返回的 errors 数组可读取 error.errors / error.data / error.extensions } else if (CombinedProtocolErrors.is(error)) { // multipart 订阅的传输层协议错误可读取 error.errors } else { // 网络错误如 ServerError携带 statusCode或其他异常 }值得一提的是error判别函数都是基于品牌标记的类型守卫isBranded用于让 TypeScript 在分支内自动收窄类型。此外仓库还提供LinkError工具src/errors/LinkError.ts它不是错误类而是记录错误是否来自 link 链的注册表可在调用方用于区分链路错误与业务代码自抛错误。自定义错误消息格式CombinedGraphQLErrors与CombinedProtocolErrors都暴露了静态的formatMessage属性可通过覆盖它来改变error.message的拼装方式需在首次执行任何操作前配置。例如用逗号连接各条消息import { CombinedGraphQLErrors } from apollo/client/errors; CombinedGraphQLErrors.formatMessage (errors) { return errors.map((error) error.message).join(, ); };重试操作返回 Observable 的进阶用法errorHandler返回ObservableApolloLink.Result时ErrorLink会转而订阅该 Observable 并将其结果转发给上游从而实现链路级重试。这是重新执行整个操作的标准姿势与用重试函数延迟重新发起请求如 retry link 中的延迟策略不同重试的是同一次操作在新 Observable 上的完整执行。import { ErrorLink } from apollo/client/link/error; import { Observable } from rxjs; const errorLink new ErrorLink(({ operation, forward, error }) { // 只对网络错误重试一次 if (error instanceof ServerError error.statusCode 500) { return forward(operation); // 重新执行操作返回新的 Observable } // 其他情况返回 void错误继续沿原路径传播 });实现细节src/link/error/index.ts回调返回 Observable 后ErrorLink会调用retriedResult?.subscribe(observer)订阅它若回调返回void则把原始result用observer.next(result)透传、把原始错误用observer.error(error)继续抛出从而不改变原有行为当重试正在进行时complete事件会被抑制if (!retriedResult)才调用observer.complete()避免重试结果未到达就提前结束取消订阅时原始订阅与重试订阅都会执行unsubscribe()防止资源泄漏。忽略与修改错误静默处理不需要的场景如果只是想让某些错误消失可以在回调中直接修改result后再返回void。测试 src/link/error/tests/index.ts 的 allows an error to be ignored 用例展示了这一用法const errorLink new ErrorLink(({ result }) { if (isFormattedExecutionResult(result)) { delete result!.errors; // 删除 errors 字段后结果被视为成功 } });删除errors后下游与调用方将不再感知到该错误。这种模式适用于部分成功可接受或错误由别的通道上报的场景。从 onError 迁移到 ErrorLinkonError函数在当前仓库中被明确标记为deprecated其实现只有一行src/link/error/index.tsexport function onError(errorHandler: ErrorLink.ErrorHandler) { return new ErrorLink(errorHandler); }迁移方式非常简单onError(fn)等价于new ErrorLink(fn)回调签名完全一致直接替换构造方式即可// 旧写法已弃用 import { onError } from apollo/client/link/error; const link onError(handler); // 新写法推荐 import { ErrorLink } from apollo/client/link/error; const link new ErrorLink(handler);增量响应defer / multipart中的错误处理ErrorLink同样覆盖增量执行协议下的错误场景。在 src/link/error/index.ts 的next处理器中错误提取逻辑会优先询问operation.client[queryManager].incrementalHandlerconst handler operation.client[queryManager].incrementalHandler; const errors handler.isIncrementalResult(result) ? handler.extractErrors(result) : result.errors;也就是说当结果被判定为增量结果如defer的后续 chunk、GraphQL 17 alpha 增量响应时错误从增量块中提取并同样包装为CombinedGraphQLErrors普通结果则读取顶层errors字段。对应的测试用例Defer20220824Handler、GraphQL17Alpha9Handler分别验证了增量块errors与completed块中的错误都能正确触发回调相关 handler 实现见 src/incremental/handlers。测试验证与行为保证src/link/error/tests/index.ts 是ErrorLink行为的事实来源它覆盖了以下关键保证GraphQL 错误触发回调result.errors存在时回调恰好调用一次入参含forward、operation、result与CombinedGraphQLErrors包装的error同步抛出与 Observable error 均能捕获下游 link 抛错、observer.error(error)、subscribe内抛错三种路径都会被捕获非常规错误类型规范化字符串被包为ErrorSymbol/对象/数组被包为UnconventionalError无错误不打扰正常数据流不会触发回调流正常完成可取消unsubscribe后回调不再触发订阅被正确清理保留上下文operation.getContext()中的自定义上下文在回调中可读。相关资源模块 API 报告.api-reports/api-report-link_error.api.md实现源码src/link/error/index.ts行为测试src/link/error/tests/index.ts官方 API 文档由该模块生成docs/source/api/link/apollo-link-error.mdx错误处理完整指南docs/source/data/error-handling.mdx配套错误类型CombinedGraphQLErrorssrc/errors/CombinedGraphQLErrors.ts、CombinedProtocolErrorssrc/errors/CombinedProtocolErrors.ts、错误模块导出src/errors/index.ts【免费下载链接】apollo-clientThe industry-leading GraphQL client for TypeScript, JavaScript, React, Vue, Angular, and more. Apollo Client delivers powerful caching, intuitive APIs, and comprehensive developer tools to accelerate your app development.项目地址: https://gitcode.com/gh_mirrors/ap/apollo-client创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
企业数字化 ERP 产品动态
相关推荐
ComfyUI 工作流模板全解析:20 类 50 个预配置工作流,3 步跑通第一次出图 ComfyUI 工作流模板全解析:20 类 50 个预配置工作流,3 步跑通第一次出图 【免费下载链接】ComfyUI-Workflows-ZHO 我的 ComfyUI 工作流合集 | My ComfyUI workflows collection 项目地址: https://gitcode.com/GitHub_Trending/co/ComfyUI-Workflows-Z… · 2026/9/20 22:21:47
Claude Code 的 CLAUDE.md 共识协议不生效?TaoToken 这样改模型通道再查加载层级 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/20 22:21:47
Umi-OCR 入门指南:免费离线 OCR,3 步让截图与扫描文件变成可搜索文字 Umi-OCR 入门指南:免费离线 OCR,3 步让截图与扫描文件变成可搜索文字 【免费下载链接】Umi-OCR OCR software, free and offline. 开源、免费的离线OCR软件。支持截屏/批量导入图片,PDF文档识别,排除水印/页眉页脚,扫描… · 2026/9/20 22:21:46
BrewUI:给Homebrew套上图形化外壳,macOS包管理可视化工具 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/21 7:28:55
电容越加辐射越大?位置决定EMC成败的整改案例 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/21 7:28:55
Silvaco TCAD实战:从DeckBuild示例库到自定义仿真工作流 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/21 7:28:55
Sails v0.11 升级指南:从 v0.10 平滑迁移到 Socket.io v1 时代的完整攻略 后端 【免费下载链接】sails Realtime MVC Framework for Node.js 项目地址: https://gitcode.com/gh_mirrors/sa/sails 点击查看 免费下载 本篇指南以官方迁移文档 docs/upgrading/To0.11.md 为核心,系统梳理 Sails v0.11 相对 v0.10 的破坏性变更&… · 2026/9/21 7:28:55
TanStack Table 客户端与服务器端数据处理选型指南:manual 选项、行模型与 Query 集成实战 TanStack Table 客户端与服务器端数据处理选型指南:manual 选项、行模型与 Query 集成实战 【免费下载链接】table 🤖 Headless UI for building powerful tables & datagrids for TS/JS - React-Table, Vue-Table, Solid-Table, Svelte-Table 项目… · 2026/9/21 7:27:55
Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化 直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡… · 2026/9/21 0:02:39
Word表格编号全攻略:从列表编号到题注交叉引用 写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技… · 2026/9/21 0:02:39
从第一个站到第二个站:独立开发者的静态网站选型与落地实践 1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&… · 2026/9/20 0:00:41
agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程 agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程 【免费下载链接】agentic-awesome-skills AAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and … · 2026/9/21 0:00:18
gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析 gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析 【免费下载链接】gin-vue-admin 🚀ViteVue3Gin拥有AI辅助的基础开发平台,企业级业务AI开发解决方案,内置mcp辅助服务,内置skills管理,… · 2026/9/21 0:00:18