NestJS 让您创建自定义装饰器来封装可重用的逻辑——最常见的是参数装饰器(从请求中提取数据)和元数据装饰器(附加由守卫/拦截器读取的数据)。它们保持代码 DRY 且表现力强。
自定义参数装饰器——提取请求数据
ts
{ createParamDecorator, } ;
= (
{
request = ctx.().();
request.;
},
);
()
() {
user;
}
createParamDecorator 构建一个参数装饰器:其函数接收 ExecutionContext,提取数据,并返回要注入的值。这用清晰、可重用的 @CurrentUser() 替代了重复的 @Req() req + req.user 访问。
// extract a specific property: @CurrentUser("email")
export const CurrentUser = createParamDecorator(
(data: string, ctx: ExecutionContext) => {
const user = ctx.switchToHttp().getRequest().user;
return data ? user?.[data] : user; // `data` is the argument passed to the decorator
},
);
// @CurrentUser("email") email: string → injects just user.email
import { SetMetadata } from "@nestjs/common";
// a @Roles() decorator that ATTACHES metadata to a route
export const Roles = (...roles: string[]) => SetMetadata("roles", roles);
// usage
@Roles("admin", "editor")
@Get("users")
listUsers() {}
// a guard reads the metadata via Reflector
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(ctx: ExecutionContext): boolean {
const roles = this.reflector.get<string[]>("roles", ctx.getHandler()); // read it
const { user } = ctx.switchToHttp().getRequest();
return !roles || roles.some(r => user.roles?.includes(r));
}
}
@Roles() + RolesGuard 组合——一个守卫通过 Reflector 读取的元数据装饰器——是基于角色的授权的规范模式。
import { applyDecorators } from "@nestjs/common";
// bundle multiple decorators into one reusable decorator
export function Auth(...roles: string[]) {
return applyDecorators(SetMetadata("roles", roles), UseGuards(AuthGuard, RolesGuard));
}
// usage: @Auth("admin") — applies metadata + guards in one decorator
创建自定义装饰器是 NestJS 中保持代码 DRY、富有表现力和可维护的重要技术。自定义参数装饰器(createParamDecorator)让您将常见的请求数据提取(如 @CurrentUser())封装到简洁、可重用的注解中——远比在每个处理器中重复 @Req() req 并深入请求对象更好。自定义元数据装饰器(SetMetadata)是 NestJS 授权模式的基础:标准的 @Roles() + RolesGuard(通过 Reflector 读取)基于角色的访问控制方法完全依赖于理解元数据装饰器。
而且组合装饰器(applyDecorators)让您捆绑相关的装饰器(例如应用守卫和元数据的 @Auth()),以实现简洁、一致的应用。
理解如何创建这些装饰器使您能够构建富有表现力、符合习语的 NestJS API,并以框架预期的方式实现常见模式(当前用户注入、RBAC)。
这将您从仅仅使用内置装饰器提升到为自己应用的需求扩展框架的声明式风格——这是真实 NestJS 项目中一项有价值的、频繁应用的技能。