TypeScript 客户端排障
本页回答:Wow TypeScript 包报的这个错是什么意思,怎样修? 在本页搜索你看到的报错。服务端的故障——命令超时、版本冲突、投影——见服务端的故障排查。
大多数请求失败以 fetcher 的 ExchangeError 到达代码;它的 message 和 cause 说明了出了什么错,服务端有应答时 await toWowError(error) 能读出 Wow 的错误码。见错误处理。
安装
| 报错 | 原因 | 修复 |
|---|---|---|
404 Not Found - GET https://registry.npmjs.org/@ahoo-wang%2fwow-client(E404) | 这些包随 Wow 9.2.0 发布 | 在此之前使用 5.x 的 @ahoo-wang/fetcher-wow 和 @ahoo-wang/fetcher-generator;见发布状态 |
WARN … unmet peer @ahoo-wang/wow-client@~9.2.0: found 9.3.0 | 应用里的 Wow 包处于不同的次版本 | 让 wow-client、wow-generator 和 wow-react 使用同一个版本 |
Cannot find module 'react/compiler-runtime' | React 低于 19 | wow-react 需要 React 19.3 或更高;不支持 React 18 |
Unsupported engine … wanted: {"node":">=22.12.0"} | Node.js 低于 22.12 | 升级 Node.js |
编译
| 报错 | 原因 | 修复 |
|---|---|---|
src/generated 中出现 TS1206: Decorators are not valid here、TS1241: Unable to resolve signature of method decorator | 生成的客户端是旧式装饰器类 | 在编译它们的 tsconfig.json 中设置 "experimentalDecorators": true |
NodeNext 下出现 TS2307: Cannot find module './generated' | Node 解析需要具体文件 | 导入 ./generated/index.js |
过滤字段上出现 TS2345,例如 'state.itmes' | 查询客户端用聚合的字段名给字段定类型 | 改正字段名;生成的 …AggregatedFields 枚举列出了它们 |
TS2305: … has no exported member 'and'(或 eq、Operator、Condition) | Condition API 在 @ahoo-wang/wow-client/legacy | 使用根入口的 filter.*;对接 Wow 8.10 服务端时从 /legacy 导入 |
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 /example/owner/… | 客户端没有 fetcher,默认 Fetcher 也没有基础地址 | 传入 { fetcher },或把服务注册为默认实例;见认证与拦截器 |
Request failed with status code 404 for http://…/example/owner/… | 生成的客户端加了网关据以路由的限界上下文前缀(example),而请求直接发给了服务 | 命令客户端传 basePath: ''、查询客户端传 contextAlias: '',或者改经网关发送 |
经网关时出现不带前缀的 404 | 前缀被清掉了,或者网关按别的别名路由 | 保留生成的默认值,或者把 basePath / contextAlias 设为网关的路由 |
Missing required path parameter: ownerId(或 tenantId),同时有 [fetcher-decorator] Path template … has placeholder(s) {ownerId} 警告 | 按所有者或租户划分的路由,没有东西填入它的变量 | 对 Fetcher 应用 CoSec 并登录,或者传 urlParams: { path: { ownerId } };见认证与拦截器 |
浏览器中出现 TypeError: Failed to fetch,控制台有 CORS 提示 | 服务不允许页面所在的源 | 在服务或网关上配置 CORS,或让 API 与页面同源 |
每个请求都是 401 | 没有令牌,或者 CoSec 没有应用到客户端所用的 Fetcher 上 | 检查客户端用的是哪个 Fetcher;见认证与拦截器 |
服务端应答
toWowError(error) 返回的错误码:
errorCode | 状态 | 原因 | 修复 |
|---|---|---|---|
CommandValidation | 400 | 命令体不满足校验规则 | 把 bindingErrors 显示在对应字段旁;见错误处理 |
IllegalArgument、IllegalState | 400 | 命令处理函数拒绝了命令 | 显示 errorMsg;需要改的是请求本身 |
NotFound | 404 | 没有该 id 的聚合或快照 | 处理不存在的情况;命令之后先等待 CommandStage.SNAPSHOT 再读取 |
RequestTimeout | 408 | 等待的阶段没在 timeoutMs 内到达 | 服务端已收到命令,它仍可能完成;读取状态,不要重发 |
DuplicateRequestId | 400 | 同一个请求 ID 发送了两次 | 第一次请求已经到达服务端;不要重发 |
EventVersionConflict、CommandExpectVersionConflict | 409 | 另一次写入抢先了 | 重新加载状态后再决定 |
QuerySchemaValidation:Field [state.items.productId] requires its declared element scope | 400 | 直接过滤了数组元素里的字段 | 用 filter.elementMatch('state.items', filter.eq('productId', …)) 匹配 |
关于字段名的 QuerySchemaValidation | 400 | 该字段在这个聚合上不可查询 | 使用生成的字段名;服务变化后重新生成 |
QuerySchemaUnavailable:No query backend is configured for aggregate | 503 | 服务没有供查询的快照存储(例如内存配置) | 配置服务的查询后端 |
Wow 8.11 及以后的服务端对带 raw() 的 /legacy 查询应答 400 | 400 | raw() 只对 Wow 8.10 有效 | 用 filter.* 改写查询 |
流
| 现象 | 原因 | 修复 |
|---|---|---|
对查询流的 for await 抛出 WowError | 服务端中途失败,以错误事件结束了流 | 像处理失败请求一样处理;见错误处理 |
生成的 …StreamCommandClient 产出一个名为 RequestTimeout(或其他错误码)而不是阶段名的事件 | 生成的流客户端使用 Fetcher 普通的事件提取器 | 对照 CommandStage 检查 event.event,或者使用会抛出 WowError 的 CommandClient.sendAndWaitStream |
流式命令在 PROCESSED 结束,errorCode 不是 Ok | 命令处理函数失败 | 逐个检查结果的 errorCode |
| 组件已经卸载,连接仍然开着 | 流既没读完也没被中止 | 传入 AbortSignal 并在清理时中止,或 break 出循环 |
生成
| 退出码或报错 | 原因 | 修复 |
|---|---|---|
退出码 2:Cannot read the OpenAPI document …: HTTP 401 Unauthorized | 文档需要凭据 | 传入 -H "Authorization: Bearer …" |
退出码 2:… no response within 30000 ms | 服务不可达或太慢 | 检查 URL,或调大 --timeout |
退出码 2:… is a Swagger 2.0 document | wow-generator 只读 OpenAPI 3.x | 先转换,例如用 swagger2openapi |
| 退出码 3 | 配置文件读不到、解析不了或校验不通过,或者 -c 指定的文件不存在 | 修正报错里点名的文件;见配置 |
| 退出码 4 | 两个 schema 或两个方法生成了同一个名字、$ref 指向不存在的内容、Wow 元数据格式不对,或开启 --strict 且有警告 | 阅读报错;用配置中的 methodNames 为方法命名 |
| 缺了某个方法,并有警告点名它的操作 | 该操作没有 operationId 或没有 tag | 在服务里给它补上两者;--strict 会把这个警告变成退出码 4 |
警告 … uses the deprecated name; rename it to wow-generator.config.json | 读取的是 fetcher-generator.config.json | 改名为 wow-generator.config.json |
| 某个聚合没有生成命令客户端或查询工厂 | 文档没有把它描述成 Wow 聚合 | 见 Wow 聚合识别 |
加 --verbose 运行可以看到每一步以及失败时的堆栈。
仍然没解决
收集失败请求的方法与 URL、状态码、Wow-Error-Code 响应头和响应体、包版本(pnpm ls @ahoo-wang/wow-client @ahoo-wang/fetcher)以及服务端的 Wow 版本,到 Ahoo-Wang/Wow 提 issue。