NestJS SetMetadata 装饰器的实现和用法
前言
SetMetadata
是 Nest.js 内置的一个装饰器方法,它用于为路由方法添加元数据。
本文涉及到两个知识点,装饰器和反射元数据。装饰器本质就是一个函数,可以用来修饰类,成员属性和方法等。反射元数据提供者了一些用来操作元数据的方法,现在主要使用社区实现的模块 reflect-metadata。之前也有文章对做过介绍,如果还不了解,可以先看一下。
SetMetadata
SetMetadata 是 Nest 内置的一个装饰器,作用是给控制器类和类的成员方法设置元数据。
先来看下 SetMetadata
的源码:
// 自定义装饰器的类型
export type CustomDecorator<TKey = string> = MethodDecorator &
ClassDecorator & {
KEY: TKey;
};
// 给类和成员方法设置元数据,内部使用了 reflect-metadata 提供的 Reflect.defineMetadata 方法
export const SetMetadata = <K = string, V = any>(
metadataKey: K,
metadataValue: V,
): CustomDecorator<K> => {
const decoratorFactory = (target: object, key?: any, descriptor?: any) => {
if (descriptor) {
Reflect.defineMetadata(metadataKey, metadataValue, descriptor.value);
return descriptor;
}
Reflect.defineMetadata(metadataKey, metadataValue, target);
return target;
};
decoratorFactory.KEY = metadataKey;
return decoratorFactory;
};
阅读源码可知,SetMetadata
的主要作用就是指定的 key
给类和函数注入元数据的装饰器。它接收两个参数,分别是描述元数据的 key 和元数据值。然后创建一个装饰器工厂函数 decoratorFactory
。
前文讲装饰器时说过,装饰器可以用在类和方法上,两种装饰器所接收的参数是不同的。类装饰器只接收类一个参数,方法装饰器可以接收类/类的原型对象,方法名和方法描述符三个参数。
decoratorFactory
方法内部会根据是否有方法描述符来判断此时是类装饰器还是方法装饰器。如果是方法装饰器,直接将元数据注入到方法本身。如果是类装饰器,则将元数据定义到类身上。设置元数据利用的是 reflect-metadata
包提供的 Reflect.defineMetadata
方法。
最后,将元数据标识 key
绑定到装饰器的 KEY
属性。这样,反射器就能根据 KEY 来访问到使用 SetMetadata
注入的元数据。
SetMetadata 的用法
按照文档中守卫部分的介绍,可以使用 @SetMetadata()
装饰器来为路由处理方法设置元数据。比如:
@Post()
@SetMetadata('roles', ['admin'])
async create(@Body() createCatDto: CreateCatDto) {
this.catsService.create(createCatDto);
}
根据上面源码的介绍,可以这里为 create
方法设置了元数据,key 为 roles
,值是一个数组 ['admin']
。
之后在守卫中,就可以利用 Reflector 根据 key 读取出用户的角色信息,比如在下面这个 RolesGuard
守卫中:
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
@Injectable()
export class RoleGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): Promise<boolean> {
// 使用 Reflector 获取路由方法的 role 元数据
const roles = this.reflector.getAllAndMerge('roles', [context.getHandler(), context.getClass()]);
console.log(roles)
return true
}
}
总结
本文介绍了 NestJS 中内置的 SetMetadata
装饰器的实现和用法,它是对 reflect-metadata
提供的方法的封装,主要用来为路由方法添加元数据。使用 SetMetadata
设置的元数据,可以使用 Reflector 反射器读取元数据。
转载自:https://juejin.cn/post/7225190353737121852