NestJS登录开发时switchMap未执行返回Observable的问题排查求助
问题根本原因
RxJS 中的 Observable 是冷发布者,只有被主动订阅的时候才会执行内部的逻辑。你遇到的两处代码不执行的问题,本质都是 Observable 没有被订阅触发。
1. 最初 userService.readByEmail 逻辑不执行的原因
你自定义返回的 Observable 内部包裹了 TypeORM 的 Promise 查询代码,只要这个 Observable 没有被订阅,内部的 userRepo.findOne 就永远不会触发。如果用 RxJS 处理 Promise 场景,不需要手动封装 Observable,直接用 from 操作符转换 Promise 更稳妥:
// user.service.ts 优化写法 import { from } from 'rxjs'; readByEmail(email: string): Observable<User> { return from(this.userRepo.findOne({ email })); }
2. 后续 switchMap 不执行、加 toPromise() 生效的原理
NestJS 的 Passport 本地策略默认会处理 Promise 类型的返回值,但默认不会自动订阅你返回的 Observable,所以你之前直接返回 Observable 的时候,整个链路的 Observable 都没有被订阅,自然 switchMap 不会触发。
你加了 .toPromise() 之后,本质就是主动订阅了 Observable,把它转换成了 Promise 交给 NestJS 处理,整条链路就通了。
优化方案推荐
你可以不用手动封装 Observable 处理 bcrypt 比对,也可以选择全程用 Promise 写法更适配 NestJS 生态,避免 RxJS 冷订阅的坑:
写法1:全程用 Promise(更适合 NestJS 常规开发)
// auth.service.ts async validateUser(email: string, password: string): Promise<User | null> { const user = await this.userService.readByEmail(email); if (!user) return null; const isPasswordValid = await bcrypt.compare(password + global.userPepper, user.password); if (!isPasswordValid) return null; const { password: _, ...validUser } = user; return validUser as User; } // user.service.ts async readByEmail(email: string): Promise<User | null> { return this.userRepo.findOne({ email }); } // local.strategy.ts async validate(email: string, password: string) { const user = await this.auth.validateUser(email, password); if (!user) throw new UnauthorizedException(); return user; }
写法2:保留 RxJS 写法的优化版
如果要保留 RxJS 用法,可以用 from 转换所有 Promise,减少手动封装 Observable 的冗余代码:
// auth.service.ts import { from, map, switchMap, of } from 'rxjs'; validateUser(email: string, password: string): Observable<User | null> { return this.userService.readByEmail(email).pipe( switchMap(user => { if (!user) return of(null); return from(bcrypt.compare(password + global.userPepper, user.password)).pipe( map(isValid => { if (!isValid) return null; const { password: _, ...validUser } = user; return validUser as User; }) ) }) ) }
内容的提问来源于stack exchange,提问作者LittleFish
相关产品推荐
相关产品推荐

