在 NestJS 中,Reflector 和 @SetMetadata 是一对常用的工具,用于在运行时管理和提取元数据。这些元数据可以用于各种场景,如权限控制、日志记录、缓存策略等。下面详细介绍它们的用法和结合示例。
1. @SetMetadata
@SetMetadata 是一个装饰器,用于在类、方法或其他装饰器上设置键值对形式的元数据。它通常用于定义一些配置信息,这些信息可以在运行时通过 Reflector 提取。
语法
@SetMetadata(key: string, value: any)- key: 元数据的键。
- value: 元数据的值,可以是任何类型。
示例
假设我们要定义一个角色元数据,用于权限控制:
直接在控制器前使用
@SetMetadata('role', ['admin'])
  @UseGuards(PersonGuard)
  @Get(':id')
  findOne(@Param('id') id: string) {
    return this.personService.findOne(+id);
  }
可以使用,但每个都使用@SetMetadata不够优雅,一般使用自定义装饰器:
nest g d roles
import { SetMetadata } from '@nestjs/common';
export const ROLES_KEY = 'roles';
export const Roles = (...roles: string[]) => SetMetadata(ROLES_KEY, roles);
在controller中直接使用自定义装饰器
//@SetMetadata('role', ['admin'])
  @Roles('admin')
  @UseGuards(PersonGuard)
  @Get(':id')
  findOne(@Param('id') id: string) {
    return this.personService.findOne(+id);
  }2. Reflector
Reflector 是一个服务,用于在运行时提取通过 @SetMetadata 设置的元数据。它通常在守卫(Guards)、拦截器(Interceptors)、管道(Pipes)等地方使用。
导入 Reflector
import { Reflector } from '@nestjs/core';使用 Reflector
Reflector 提供了多个方法来提取元数据,常用的有:
- get<T>(metadataKey: string, target: object): T: 从目标对象(类或方法)中获取指定键的元数据。
- getAllAndOverride<T>(metadataKey: string, context: ExecutionContext): T: 从执行上下文中获取并覆盖指定键的元数据。
- getAllAndMerge<T>(metadataKey: string, context: ExecutionContext): T: 从执行上下文中获取并合并指定键的元数据。
示例
假设我们要创建一个 PersonGuard 守卫,用于检查用户是否有访问特定路由的权限:
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
@Injectable()
export class PersonGuard implements CanActivate {
  constructor(private readonly reflector: Reflector) {}
  canActivate(
    context: ExecutionContext,
  ): boolean | Promise<boolean> | Observable<boolean> {
    const requiredRoles = this.reflector.get<string[]>('roles', context.getHandler());
    if (!requiredRoles) {
      return true; // 如果没有设置角色要求,则允许访问
    }
    const request = context.switchToHttp().getRequest();
    const user = request.user; // 假设用户信息存储在请求对象中
    if (!user || !user.roles) {
      return false; // 如果用户没有角色信息,则拒绝访问
    }
    return requiredRoles.some(role => user.roles.includes(role));
  }
}3. 总结
- @SetMetadata: 用于在类、方法或其他装饰器上设置键值对形式的元数据。
- Reflector: 用于在运行时提取通过- @SetMetadata设置的元数据,常用于守卫、拦截器、管道等场景。
通过结合使用 @SetMetadata 和 Reflector,你可以在 NestJS 中实现灵活且可配置的逻辑,如权限控制、日志记录、缓存策略等。
 
                            