在 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 中实现灵活且可配置的逻辑,如权限控制、日志记录、缓存策略等。