如何在Nest.js GraphQL订阅中使用Ix AsyncIterator及相关报错排查
问题根因
NestJS GraphQL的订阅处理器默认要求AsyncIterator产出的是完整的查询响应对象,而非字段的直接值。你当前直接产出数字类型值,处理器会尝试从值中读取与订阅字段同名的counter属性,数字类型不存在该属性,最终取到null值,触发非空字段报错。
解决方案
方案1:调整AsyncIterator的产出结构
每次产出的对象包含和订阅字段同名的属性即可,两种代码实现修改如下:
原生AsyncGenerator版本
async function* generateSequence(start, end) { for (let i = start; i <= end; i++) { await new Promise((resolve) => setTimeout(resolve, 1000)); // 嵌套与字段名对应的对象结构 yield { counter: i }; } } @Resolver((of) => –) export class TestResolver { constructor() {} @Subscription((returns) => Number) counter(): AsyncIterator<number> { return generateSequence(1, 100); } }
Ix实现版本
import { map } from 'ix/operators'; @Resolver((of) => –) export class TestResolver { constructor() {} @Subscription((returns) => Number) counter(): AsyncIterator<number> { return from([1, 2, 3, 4, 5, 6]).pipe( map(num => ({ counter: num })) )[Symbol.asyncIterator](); } }
方案2:通过resolve参数提取字段值
如果不想修改AsyncIterator的产出逻辑,可以在@Subscription装饰器中新增resolve配置,手动指定字段返回值的提取规则:
async function* generateSequence(start, end) { for (let i = start; i <= end; i++) { await new Promise((resolve) => setTimeout(resolve, 1000)); // 保持原有直接产出数字的逻辑 yield i; } } @Resolver((of) => –) export class TestResolver { constructor() {} @Subscription(() => Number, { resolve: (rawValue) => rawValue }) counter(): AsyncIterator<number> { return generateSequence(1, 100); } }
额外检查项
如果修改后仍然报错,可以确认两点:
- 你的GraphQL Schema中
Subscription.counter字段是否定义为非空类型,确保AsyncIterator不会产出undefined、null值 - 确认NestJS配置中已经正确启用订阅传输层(subscriptions-transport-ws或graphql-ws)
内容的提问来源于stack exchange,提问作者DaSch
相关产品推荐
相关产品推荐

