NestJS中SSE事件为空问题排查及DTO适配疑问
NestJS SSE 事件推送数据为空问题解决
问题根源
全局配置的ClassSerializerInterceptor使用了strategy: 'excludeAll'策略,会自动排除所有未通过@Expose标注的属性。而MessageEvent的data是访问器属性(getter),并非实例的可枚举自有属性,直接用plainToInstance转换时无法自动捕获该属性,导致前端拿到的event.data为空。
解决方案
方案1:手动给SSEDto赋值data属性
在映射时,先通过plainToInstance转换其他属性,再手动将MessageEvent的data赋值给SSEDto实例:
return fromEvent(this.eventEmitter, 'new-order') .pipe( map(() => { const message = { hello: 'world' }; const event = new MessageEvent('new-order', { data: message }); const sseDto = plainToInstance(SSEDto, event); // 手动赋值data sseDto.data = event.data; return sseDto; }) );
方案2:通过@Transform注解自动映射data
修改SSEDto,给data属性添加@Transform注解,从原始MessageEvent对象中读取data:
import { Expose, Transform } from 'class-transformer'; export class SSEDto { @Expose() @Transform(({ obj }) => obj.data) // 从MessageEvent实例中获取data data: string | object; @Expose() id?: string; @Expose() type?: string; @Expose() retry?: number; @Expose() defaultPrevented: boolean; @Expose() cancelable: boolean; @Expose() timeStamp: Timestamp; }
之后直接使用plainToInstance转换即可自动获取data。
方案3:给SSE接口单独禁用全局拦截器策略
如果不想修改DTO,可以在SSE方法上添加@SerializeOptions注解,覆盖全局的excludeAll策略:
import { SerializeOptions } from '@nestjs/common'; @Sse('sse') @SerializeOptions({ strategy: 'default', excludeExtraneousValues: false, }) sse(): Observable<MessageEvent> { return interval(1000).pipe(map((_) => ({ data: { hello: 'world' } }) as MessageEvent)); }
或者重新指定拦截器,使用默认策略:
import { UseInterceptors } from '@nestjs/common'; import { ClassSerializerInterceptor } from '@nestjs/common/serializer'; @Sse('sse') @UseInterceptors(new ClassSerializerInterceptor(app.get(Reflector), { strategy: 'default', })) sse(): Observable<MessageEvent> { // 原有逻辑 }
内容的提问来源于stack exchange,提问作者Michał B
相关产品推荐
相关产品推荐

