Nest Interceptor异步方法失效及Token验证不生效问题求助
问题分析与解决方案
核心问题原因
- 校验时机错误:你把token校验逻辑放在了
tap操作符中,而tap是在API请求处理完成(控制器逻辑执行完毕)后才会触发的回调。这意味着无论请求是否携带合法token,API都会先执行完业务逻辑,之后才进入校验逻辑,此时再设置响应状态已经无法阻止API返回结果。 - 异步操作未正确等待:
processRequest是异步函数,但tap不会等待异步操作完成,导致用户访问次数和IP的保存操作可能还没执行完,响应就已经返回给客户端了。 - 直接操作Response对象不符合Nest规范:Nest框架有自己的异常处理机制,直接修改
res.status会绕过这套机制,导致异常无法被正确捕获和格式化。
修复后的代码实现
import { Injectable, NestInterceptor, ExecutionContext, CallHandler, UnauthorizedException } from '@nestjs/common'; import { Observable } from 'rxjs'; import { switchMap, tap } from 'rxjs/operators'; import { Model } from 'mongoose'; import { User } from '../entity/user-entity'; import { InjectModel } from '@nestjs/mongoose'; import { Request } from 'express'; @Injectable() export class ResponseInterceptor implements NestInterceptor { constructor(@InjectModel(User.name) private userModel: Model<User>) { } intercept(context: ExecutionContext, next: CallHandler): Observable<any> { console.log("Before...") const req = context.switchToHttp().getRequest<Request>(); // 前置校验token,提前终止非法请求 const token = req.headers.authorization?.split(' ')[1]; if (!token) { throw new UnauthorizedException('Missing token'); } // 使用switchMap处理异步逻辑,确保校验完成后再执行API逻辑 return this.processRequest(req, token).pipe( switchMap(() => next.handle()), // 请求完成后更新访问统计 tap(() => this.updateAccessStats(req, token)) ); } private async processRequest(req: Request, token: string): Promise<void> { const user = await this.userModel.findOne({ token }).exec(); if (!user) { throw new UnauthorizedException('Invalid token'); } // 将用户信息挂载到请求对象,供后续控制器使用 req.user = user; } private async updateAccessStats(req: Request, token: string): Promise<void> { try { const user = await this.userModel.findOne({ token }).exec(); if (user) { user.hitCount += 1; user.ipAndResponses.push({ ipAddress: req.ip, response: req.res?.statusCode || 200 }); await user.save(); } } catch (error) { console.error('Error updating user access stats:', error); } } }
关键改动说明
- 前置token校验:将token校验逻辑移到
next.handle()之前,一旦发现无token或无效token,直接抛出UnauthorizedException,终止请求流程,API逻辑不会被执行。 - 异步逻辑用switchMap处理:通过
switchMap等待processRequest异步校验完成后,再执行API逻辑,确保权限校验通过后才进入业务处理。 - 拆分统计更新逻辑:将访问次数和IP的更新放到
tap中(请求完成后执行),避免阻塞API响应,同时用单独的异步函数处理,确保操作完成。 - 使用Nest内置异常:用
UnauthorizedException代替直接修改res.status,让框架统一处理响应格式,符合Nest的开发规范。
内容的提问来源于stack exchange,提问作者Narendra Singh
相关产品推荐
相关产品推荐

