TypeScript 客户端故障排查
在本页搜索你看到的消息。
安装
| 消息 | 原因 | 修复 |
|---|---|---|
unmet peer @ahoo-wang/wow-client@~x.y.z: found … | 应用的 Wow 包处于不同的次版本 | 每个 Wow 包都安装同一个版本(兼容性与版本) |
Cannot find module 'react/compiler-runtime' | React 版本低于 19 | wow-react 和视图引擎需要 React 19 或更高版本 |
pnpm add 安装了 9.x | latest 指向最新的稳定版本;Wow 10 的预发布版本在它自己的 dist-tag 上 | 安装你的服务所用的版本,或者预发布版本的 dist-tag(发布状态) |
编译
| 消息 | 原因 | 修复 |
|---|---|---|
过滤字段上的 TS2345,例如 'status' 或 'state.statsu' | 查询客户端为它的字段提供类型:系统字段,以及生成的 <Aggregate>StateField。状态字段位于 state. 之下 | 写成 state.status;服务改变了的话就重新生成 |
金额或 ID 上的 TS2322: Type 'number' is not assignable to type 'string' | Long、BigInteger 或 BigDecimal 字段是 string,精确地读取和写入 | 以文本传入它的数字:unitPrice: '19.90'(精确数字) |
查询记录上的 TS2339: Property '…' does not exist | 查询的 projection.include 没有包含那条路径,结果被收窄到它包含的内容 | 包含这条路径,或者去掉投影 |
NodeNext 下的 TS2307: Cannot find module './generated' | Node 解析需要指向文件 | 导入 ./generated/index.js |
TS2882: Cannot find module or type declarations for side-effect import of '…/styles.css' | TypeScript 6 会检查副作用导入 | Vite 项目通过 vite/client 声明 *.css;其他项目加上 declare module '*.css'; |
发送请求
| 消息 | 原因 | 修复 |
|---|---|---|
Failed to parse URL from /eshop-ordering/… | 客户端没有 fetcher,而默认的 Fetcher 没有基础 URL | 用 { fetcher } 创建客户端(发送命令) |
带 about:blank problem 的 404 | 请求所到之处没有这个路由:网关没有路由该上下文的前缀,或者 basePath 不是它所期望的 | 发往提供 /<context>/… 的服务或网关 |
TypeError: The path … needs id. | 作用于已有聚合的命令带着空 ID 发送 | 传入聚合的 ID |
浏览器中的 TypeError: Failed to fetch,控制台中有 CORS 消息 | 服务不允许页面的来源 | 在服务或网关上配置 CORS,或者从页面的同源提供 API |
每个请求都是 401 wow.auth.unauthenticated | 没有令牌,或者客户端所用的 Fetcher 没有发送令牌 | 对那个 Fetcher 应用 CoSec 并登录(认证与拦截器) |
服务的回答
拒绝以 WowProblemError reject;它的 code 是下面这些之一,或者生成的 <Context>ErrorCodes 中的某个领域错误码。全部错误码见错误码。
code | 状态 | 原因 | 修复 |
|---|---|---|---|
领域错误码 <context>.<aggregate>.<name> | 除非服务另行指定,否则为 422 | 聚合拒绝了命令 | 显示 problem.detail;请求本身需要改变 |
wow.command.invalid | 400 | 命令未通过校验 | 在每个 violations 的 path 旁边显示它 |
wow.aggregate.not-found | 404 | 没有那个 ID 的聚合 | 处理不存在的情况 |
wow.aggregate.version-mismatch | 409,带 expectedVersion 时为 412 | 另一次写入抢先了 | 重新读取状态,再决定一次 |
wow.command.request-id-reused | 409 | 请求 ID 已被另一条命令使用 | 为新命令生成新的请求 ID |
wow.wait.timeout | 504 | 等待用完了时间;命令可能已经提交 | 用同一个请求 ID 重试,或者读取状态 |
wow.wait.invalid | 400 | 等待计划不是服务能跟随的链 | 用每个上下文生成的各跳构建计划 |
wow.query.invalid | 400 | 查询违反了查询模型的规则 | 读取每个 violation 的 code 和 path |
wow.query.min-version-not-reached | 409 | 读取的 minVersion 在等待时间内没有达到 | 在 retry.afterMs 之后重试;problem 的 version 是当前的版本 |
wow.command.busy、wow.query.busy | 429 | 聚合、节点或存储繁忙 | 在 retry.afterMs 之后重试 |
wow.node.standby | 503 | 服务在迁移切换之前处于待机,只提供读取 | 稍后重试 |
error.retry 说明重试能否成功,以及是否保留请求 ID。
流
| 症状 | 原因 | 修复 |
|---|---|---|
| 命令流在计划的最后一跳之前结束 | 途中的某个 Saga 没有再发出任何东西:最后一个结果带有 chainEnded,pending 列出不会到来的各跳 | 把它当作链的终点,就像 eShop 的结账在支付被拒时那样 |
命令流的最后一个结果不是 SUCCEEDED | 命令,或链所导向的某条命令,在准入之后被拒绝或失败 | 读取结果的 status 和 error |
查询流以 WowProblemError 出错 | 服务在中途以一个客户端无法越过续读的 problem 失败 | 像处理失败的请求一样处理它 |
| 组件已经消失,连接仍保持打开 | 流从未读到结束,也没有被取消 | 传入一个 signal 并在清理时中止它,或者取消读取器 |
生成
| 退出码或消息 | 原因 | 修复 |
|---|---|---|
| 退出码 2 | 输入无法读取或获取,既不是 Manifest 也不是 OpenAPI 3 文档,或者某个选项不对 | 阅读消息;需要凭据的 http(s) 输入要带 -H 'Authorization: Bearer …' |
| 退出码 3 | 配置无法读取、解析或校验 | 修正消息指出的文件(配置) |
| 退出码 4 | 文档无法生成,或者设置了 --strict 而运行记录了警告 | 阅读这次运行的警告 |
| 退出码 5 | 输出无法写入、某条路径越出了输出目录,或者更新版本的生成器写了它的 .wow-generator.json | 用写出它的那个版本的生成器生成 |
| 提交的客户端与新一次运行的结果不同 | Manifest 基线变了,或者生成器的版本变了 | 把新的输出与导致它的改变一起提交 |
用 --verbose 运行,可以看到每一步以及失败的堆栈。
仍然解决不了
收集失败请求的方法和 URL、状态、problem 的内容及其 Wow-Request-Id、包的版本(pnpm ls @ahoo-wang/wow-client @ahoo-wang/fetcher)以及服务的 Wow 版本,然后在 Ahoo-Wang/Wow 提交 issue。