Nestjs项目实战 定制化装饰器开发与应用
在Nestjs项目中使用定制化装饰器时遇到几个问题想请教:
- 如何为不同的业务场景设计可复用的装饰器?比如权限验证和日志记录这类通用功能,有没有最佳实践参考?
- 装饰器的执行顺序有时会出现混乱,比如中间件装饰器和自定义装饰器之间的优先级如何控制?
- 能否分享一个结合参数装饰器和方法装饰器的实际案例?官方文档的例子比较基础,想了解复杂场景下的应用方式。
- 自定义装饰器在单元测试中如何模拟?特别是依赖了其他服务实例的装饰器该怎么测试?
最近在网关层开发中频繁用到装饰器,希望能得到一些实战经验指导。
3 回复
在NestJS项目中,定制化装饰器可以极大提升代码复用性和可维护性。例如创建一个验证用户权限的自定义装饰器:
import { Injectable } from '@nestjs/common';
export const Permission = (permissions: string[]) => {
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
const originalMethod = descriptor.value;
descriptor.value = async function (...args: any[]) {
const userPermissions = args[0].user.permissions; // 假设从上下文获取用户权限
const hasPermission = permissions.some(p => userPermissions.includes(p));
if (!hasPermission) {
throw new Injectable('Forbidden', 403);
}
return originalMethod.apply(this, args);
};
};
};
使用时只需在控制器方法上添加@Permission(['admin'])
即可校验权限。记得在全局异常过滤器中处理403错误返回统一响应。
此装饰器通过拦截方法执行,检查用户权限并决定是否放行请求。这种方式能显著减少重复权限校验代码,使业务逻辑更加清晰。
在NestJS中,定制化装饰器是一种强大的工具,能够提升代码复用性和可读性。首先,创建一个装饰器需要使用@nestjs/common
提供的createParamDecorator
方法。例如,定义一个获取请求用户ID的装饰器:
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
export const UserId = createParamDecorator(
(data: unknown, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
return request.user.id;
},
);
在控制器方法中可以这样使用:async update(@UserId() userId: number)
。
对于更复杂的装饰器,可以直接操作类、方法或属性。比如自定义验证装饰器:
import { registerDecorator, ValidationArguments, ValidationOptions } from 'class-validator';
export function IsPositive(validationOptions?: ValidationOptions) {
return (object: any, propertyName: string) => {
registerDecorator({
name: 'isPositive',
target: object.constructor,
propertyName,
options: validationOptions,
validator: {
validate(value: any, args: ValidationArguments) {
return value > 0;
},
},
});
};
}
通过装饰器的应用,可以实现逻辑解耦,增强代码的模块化和维护性。同时注意装饰器的命名规范和功能单一性,便于团队协作和后期扩展。
NestJS 定制化装饰器开发与应用
在NestJS中,装饰器是框架的核心概念之一,允许您以声明式的方式增强类和类成员的功能。下面是自定义装饰器的开发和应用方法。
1. 装饰器类型
NestJS支持三种主要类型的装饰器:
- 参数装饰器
- 方法装饰器
- 类装饰器
2. 创建简单参数装饰器
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
export const User = createParamDecorator(
(data: string, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
const user = request.user;
return data ? user?.[data] : user;
},
);
使用方式:
@Get()
async findOne(@User('firstName') firstName: string) {
console.log(`Hello ${firstName}`);
}
3. 方法装饰器示例
import { SetMetadata } from '@nestjs/common';
export const Roles = (...roles: string[]) => SetMetadata('roles', roles);
使用方式:
@Post()
@Roles('admin')
async create() {
// 仅管理员可访问
}
4. 组合装饰器
import { applyDecorators } from '@nestjs/common';
import { ApiOkResponse, ApiOperation } from '@nestjs/swagger';
export function ApiGetUser() {
return applyDecorators(
ApiOperation({ summary: '获取用户信息' }),
ApiOkResponse({ description: '返回用户信息' })
);
}
5. 装饰器应用场景
- 权限控制:创建@AdminOnly、@Public等装饰器
- 日志记录:自动记录方法调用
- 缓存控制:自动缓存响应
- 参数转换:自动转换传入参数格式
- 响应处理:统一响应格式
6. 最佳实践
- 保持装饰器职责单一
- 为装饰器提供清晰的文档
- 考虑装饰器的执行顺序
- 避免过度使用装饰器
定制化装饰器可以显著提高代码的可读性和可维护性,是NestJS开发中非常强大的工具。