You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Nest Interceptor异步方法失效及Token验证不生效问题求助

问题分析与解决方案

核心问题原因

  1. 校验时机错误:你把token校验逻辑放在了tap操作符中,而tap是在API请求处理完成(控制器逻辑执行完毕)后才会触发的回调。这意味着无论请求是否携带合法token,API都会先执行完业务逻辑,之后才进入校验逻辑,此时再设置响应状态已经无法阻止API返回结果。
  2. 异步操作未正确等待:processRequest是异步函数,但tap不会等待异步操作完成,导致用户访问次数和IP的保存操作可能还没执行完,响应就已经返回给客户端了。
  3. 直接操作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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 19:14:55