NestJS使用useGlobalGuards、useGlobalPipes时如何排除指定端点?
全局守卫/管道排除指定接口解决方案
可以实现该需求,核心思路是通过NestJS原生的元数据机制给需要排除的接口打标记,在全局守卫/管道中读取标记后跳过对应逻辑,该方案同时适配useGlobalGuards和useGlobalPipes场景。
全局守卫(useGlobalGuards)实现步骤
步骤1:定义公共接口标记装饰器
// src/common/decorators/public.decorator.ts import { SetMetadata } from '@nestjs/common'; export const IS_PUBLIC_KEY = 'isPublic'; export const Public = () => SetMetadata(IS_PUBLIC_KEY, true);
步骤2:改造AuthGuard增加公共接口判断逻辑
注入Reflector工具类读取元数据,优先放行标记为公共的接口:
// src/common/guards/auth.guard.ts import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; import { IS_PUBLIC_KEY } from '../decorators/public.decorator'; @Injectable() export class AuthGuard implements CanActivate { constructor(private reflector: Reflector) {} canActivate(context: ExecutionContext): boolean | Promise<boolean> { // 同时支持接口级别和控制器级别的公共标记 const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [ context.getHandler(), context.getClass(), ]); // 公共接口直接跳过校验 if (isPublic) return true; // 原有令牌校验逻辑保持不变 const request = context.switchToHttp().getRequest(); // ... 你的令牌校验逻辑 } }
步骤3:给需要跳过校验的接口添加装饰器
直接在控制器或者单个接口上添加@Public()即可:
// src/user/user.controller.ts import { Public } from '../common/decorators/public.decorator'; import { Post, Body, Controller } from '@nestjs/common'; @Controller('user') export class UserController { // 单个接口标记为公共 @Public() @Post('register') register(@Body() registerDto: any) { // 注册逻辑 } // 其余接口仍走全局校验 @Post('profile') getProfile() { return {} } }
全局管道(useGlobalPipes)适配方案
同样可以通过自定义元数据实现排除逻辑,步骤如下:
- 自定义
@SkipValidation装饰器标记不需要校验的接口 - 继承官方
ValidationPipe实现自定义管道,读取元数据后跳过对应校验
示例代码:
// 定义跳过校验装饰器 import { SetMetadata } from '@nestjs/common'; export const SKIP_VALIDATION_KEY = 'skipValidation'; export const SkipValidation = () => SetMetadata(SKIP_VALIDATION_KEY, true); // 自定义全局校验管道 import { ValidationPipe, ArgumentMetadata, Injectable } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; @Injectable() export class CustomValidationPipe extends ValidationPipe { constructor(private reflector: Reflector) { super({ transform: true }); } transform(value: any, metadata: ArgumentMetadata) { const isSkip = this.reflector.get(SKIP_VALIDATION_KEY, metadata.metatype); if (isSkip) return value; return super.transform(value, metadata); } }
内容的提问来源于stack exchange,提问作者Lucas
相关产品推荐
相关产品推荐

