Huly 平台客户端接入指南:基于 @hcengineering/client-resources 构建与运行你的 Client

发布时间:2026/9/10 19:35:24
Huly 平台客户端接入指南:基于 @hcengineering/client-resources 构建与运行你的 Client Huly 平台客户端接入指南基于 hcengineering/client-resources 构建与运行你的 Client【免费下载链接】platformHuly — All-in-One Project Management Platform (alternative to Linear, Jira, Slack, Notion, Motion)项目地址: https://gitcode.com/GitHub_Trending/platform80/platform导读本文围绕 Huly 平台核心包之一hcengineering/client-resources位于 foundations/core/packages/client-resources展开系统讲解如何创建一个与正在运行的 Huly 平台交互的客户端Client。你将掌握GetClient的完整调用链、Token 与连接地址的拼接规则、模型过滤FilterMode与 IndexedDB 持久化原理、Node.js 环境下 WebSocket 工厂的配置方法以及连接心跳、重连、二进制协议等底层容错机制可直接照搬文中代码集成到自己的脚本或服务中。一、包概览client-resources 在整个 Huly 平台中的定位hcengineering/client-resources是一个平台资源包它不直接提供 API 类而是以 Huly 平台标准的plugin资源形式暴露一个名为GetClient的函数资源供应用层按需加载。从 package.json 可以看到它的核心依赖hcengineering/client定义ClientFactoryOptions、ClientSocketFactory、FilterMode等类型与元数据client/src/index.tshcengineering/core提供Client、Tx、TxHandler、createClient、ClientConnectEvent等核心抽象core/src/client.tshcengineering/rpc提供 RPC 编解码RPCHandler与HelloRequest/HelloResponse握手协议hcengineering/platform提供getMetadata、setPlatformStatus、Status等平台基础设施snappyjs用于服务端推送数据的 Snappy 解压。该包自带jest测试npm test覆盖了 WebSocket 连接层与客户端集成层后续章节会结合这些测试说明实际行为。二、快速开始三步拿到可用的 Client官方 readme 给出了最简用法完整代码如下import clientResources from hcengineering/client-resources import core, { Client } from hcengineering/core // token 通过登录/账号服务获得内容为 JWT 格式见下文 Token 解析一节 const token ... // transactorUrl 为 Huly 平台的事务服务transactor端点如 https://host/api/transactor const connection: Client await (await clientResources()).function.GetClient(token, transactorUrl) // 至此 client 已可用可以执行 findAll / tx 等操作 // 使用 close 优雅关闭连接 await connection.close()要点拆解clientResources()是一个异步工厂函数调用后返回{ function: { GetClient } }结构见 src/index.ts 的默认导出GetClient(token, endpoint, opt?)返回PromiseClient其中Client接口由hcengineering/core定义调用close()会关闭底层 WebSocket 并拒绝所有未完成的请求务必在退出前调用。三、GetClient 内部实现从 Token 到连接GetClient的签名是(token: string, endpoint: string, opt?: ClientFactoryOptions): PromiseClient其内部做了三件关键事情源码位于 src/index.ts。3.1 Token 解析与合法性校验GetClient先把 JWT Token 的 payload 段token.split(.)[1]做atob解码并JSON.parse得到workspace与account两个字段decodeTokenPayload与getWSFromToken两个函数src/index.tsinterface TokenPayload { workspace?: WorkspaceUuid account?: PersonUuid extra?: any }如果 payload 中缺少workspace或account会直接抛出Workspace or account not found in token。也就是说Token 中必须携带工作区与账号信息客户端才能正确建立工作区上下文。3.2 连接 URL 拼接真正的 WebSocket 地址由concatLink(endpoint,/${token})生成src/index.ts即transactorUrl/token形式随后connect()见 src/connection.ts创建Connection实例并在 socket 打开后于 URL 末尾追加?sessionId...用于断线重连时的会话恢复见 src/connection.ts。3.3 服务端推送的事务拦截连接建立后所有服务端下推的事务Tx会先经过upgradeHandler过滤src/index.ts收到TxModelUpgrade触发opt?.onUpgrade?.()提示应用层模型已升级需要重建客户端收到TxWorkspaceEvent且事件为MaintenanceNotification通过setPlatformStatus抛出Severity.WARNING级别的维护提醒附带的timeMinutes与message参数会透传给 UI。四、模型过滤FilterMode 的三种模式GetClient会读取平台元数据client.metadata.FilterModel默认none与client.metadata.ExtraFilter默认[]构造一个ModelFilter回调传给createClientsrc/index.ts。三种取值定义于 client/src/index.ts行为如下FilterModel行为none不过滤原样返回全部模型事务client过滤掉所有server-前缀插件与未启用插件并剔除workbench:class:Application、view:class:Action、notification:class:NotificationGroup等 20 余类 UI 专属模型元素见returnClientTxes的toExclude集合src/index.tsui过滤掉所有服务端元素与未被启用的 UI 元素额外叠加ExtraFilter中列出的插件 IDreturnUITxessrc/index.ts// 示例在创建 Client 前设置过滤模式与额外排除项 import client from hcengineering/client import { setMetadata } from hcengineering/platform setMetadata(client.metadata.FilterModel, ui) setMetadata(client.metadata.ExtraFilter, [my-private-plugin])ExtraPlugins元数据则用于在ui模式下把额外插件纳入允许加载集合src/index.ts。五、模型持久化IndexedDB 缓存createModelPersistence(workspace)src/index.ts在浏览器环境下会打开indexedDB.open(model.db.persistence, 2)并在其中建立model对象仓库keyPath 为id以workspace 为键缓存LoadModelResponseload按 workspace 读取缓存模型若无缓存返回{ full: false, transactions: [], hash: }store把拉取到的模型写入缓存下次启动可跳过全量加载可通过client.metadata.OverridePersistenceStore传入自定义的TxPersistenceStore覆盖默认实现。六、Node.js 环境必须配置 WebSocket 工厂readme 中特别强调在 Node.js 环境必须用ws包替换默认 WebSocket 实现。原因是浏览器环境下Connection直接使用全局WebSocket而 Node.js 没有该全局对象需要通过client.metadata.ClientSocketFactory元数据注入wsimport client from hcengineering/client import { setMetadata } from hcengineering/platform import WebSocket from ws // 用 ws 覆盖默认的 WebSocket 工厂 setMetadata(client.metadata.ClientSocketFactory, (url) new WebSocket(url)) const connection: Client await (await clientResources()).function.GetClient(token, transactorUrl) // ... await connection.close()ClientSocketFactory的类型为(url: string) ClientSocket其中ClientSocket是平台自定义的最小 WebSocket 抽象onmessage/onclose/onopen/onerror/send/close/readyState见 client/src/index.ts因此任何符合该形状的实现浏览器 WebSocket、ws、mock 对象都可以注入。ws已声明为 devDependenciespackage.json用于测试与 Node 侧运行。七、ClientFactoryOptions 完整参数GetClient的第三个可选参数opt类型为ClientFactoryOptions定义于 client/src/index.ts逐项说明参数类型作用socketFactoryClientSocketFactory按连接 URL 创建 socket优先级最高高于全局ClientSocketFactory元数据useBinaryProtocolboolean是否使用二进制 RPC 协议默认取元数据UseBinaryProtocol再回退到truesrc/connection.tsuseProtocolCompressionboolean是否启用 Snappy 压缩默认取元数据UseProtocolCompression回退到falsesrc/connection.tsconnectionTimeoutnumber连接超时毫秒大于 0 时启用超时未连接会触发onDialTimeout并拒绝连接 Promisesrc/index.tsonHello(serverVersion?: string) boolean收到服务端hello响应含版本号时回调返回false将主动断开src/connection.tsonUpgrade() void检测到模型升级时回调onError(err: StatusCode) void服务端返回terminate错误如工作区归档/不存在时回调onConnect(event, lastTx, data) Promisevoid连接/重连/维护等事件回调event为ClientConnectEventonDialTimeout() void \| Promisevoid拨号超时回调ctxMeasureContext指标上下文用于性能埋点useGlobalRPCHandlerboolean为true时共享全局RPCHandler默认每个连接新建一个src/connection.tsClientConnectEvent枚举core/src/client.ts包含Connected首次连接并收到完整模型、Reconnected重连后应用增量、Upgraded收到全量新模型需重建、Refresh需要刷新查询、Maintenance工作区维护中。八、连接生命周期与容错机制Connection类src/connection.ts是连接层的核心值得关注的机制包括握手协议socket 打开后立即发送hello请求携带binary与compression标志服务端以hello响应确认协议能力并返回lastHash、serverVersion、account随后才把连接视为可用helloReceived truesrc/connection.ts心跳保活以 10 秒为周期发送pingpingConst ping若 5 分钟hangTimeout未收到 pong 则判定挂死并关闭 socket 触发重连src/connection.ts、src/connection.ts拨号超时30 秒dialTimeout内未完成握手会回调onDialTimeout并强制重建连接src/connection.ts自动重连与退避socket 关闭时自动scheduleOpen(forcetrue)错误发生后delay从 1 递增至上限 3 秒进行指数退避src/connection.ts、src/connection.ts会话恢复sessionId会写入sessionStorage页面刷新后重连时携带原 sessionId服务端据此恢复订阅src/connection.ts限流保护服务端返回的rateLimit信息被实时跟踪remaining过低时引入slowDownTimer主动限速剩余为 0 时按retryAfter延迟重试src/connection.ts分块响应findAll大结果集支持chunk分片客户端按index排序拼接后再 resolvesrc/connection.ts去重与重试once请求会按 methodparams 去重非幂等tx在重连时会先查询事务是否已提交再决定是否重发src/connection.ts、src/connection.ts。九、Client 常用操作连接建立后Client提供完整的存储与查询 APIClientImpl见 core/src/client.ts常用方法包括// 查询findAll / findOne const tasks await connection.findAll(core.class.Tx, { objectClass: tracker:class:Issue }, { limit: 20 }) const one await connection.findOne(core.class.Space, { name: My Space }) // 写入提交事务 await connection.tx(tx) // 模型相关 await connection.getHierarchy() await connection.getModel()底层 RPC 方法在 src/connection.ts 中均有对应实现loadModel、findAll、tx、loadChunk、getDomainHash、searchFulltext、domainRequest、sendForceClose等可作为排查网络问题的参考。十、测试验证连接层与集成层该包用 Jest 覆盖了两层行为是理解契约的最佳范例连接层单测src/tests/connection.test.ts自定义MockWebSocket模拟hello、loadModel、findAll、tx响应与ping/pong回包验证connect()能建立连接并正确分发服务端下推的事务集成测试src/tests/integration.test.ts提供MockClientConnection与createTestClient()辅助函数覆盖事务端到端流转、findAll/findOne/searchFulltext/domainRequest、连接断开恢复、多 handler 分发、Upgraded/Maintenance事件以及并发事务提交等场景。运行测试npm test --prefix foundations/core/packages/client-resources十一、常见问题排查Node.js 下WebSocket is not defined未设置client.metadata.ClientSocketFactory按第六节注入ws即可报错Workspace or account not found in tokenToken 的 payload 段缺少workspace/account字段请检查登录流程签发的 Token 内容连接长时间不建立确认transactorUrl正确且可达并观察connectionTimeout是否过小可在opt或ConnectionTimeout元数据中调整模型升级后行为异常监听onUpgrade回调并重建 ClientClientConnectEvent.Upgraded语义见 core/src/client.ts需要最小化模型体积为FilterModel元数据设置client或ui结合ExtraFilter排除不需要的插件。总结hcengineering/client-resources是 Huly 平台所有客户端接入的统一入口GetClient负责 Token 校验、URL 拼接、模型过滤与本地持久化底层Connection则封装了 WebSocket 握手、心跳、重连、限流与二进制/压缩协议等全部传输细节。无论你是编写浏览器端插件、Node.js 脚本还是测试工具只需提供合法 Token 与 transactor 端点并在 Node 侧正确注入ws工厂即可获得功能完整、具备断线自愈能力的平台客户端。【免费下载链接】platformHuly — All-in-One Project Management Platform (alternative to Linear, Jira, Slack, Notion, Motion)项目地址: https://gitcode.com/GitHub_Trending/platform80/platform创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询