Nestjs项目实战 定制化装饰器开发与应用

在Nestjs项目中使用定制化装饰器时遇到几个问题想请教:

  1. 如何为不同的业务场景设计可复用的装饰器?比如权限验证和日志记录这类通用功能,有没有最佳实践参考?
  2. 装饰器的执行顺序有时会出现混乱,比如中间件装饰器和自定义装饰器之间的优先级如何控制?
  3. 能否分享一个结合参数装饰器和方法装饰器的实际案例?官方文档的例子比较基础,想了解复杂场景下的应用方式。
  4. 自定义装饰器在单元测试中如何模拟?特别是依赖了其他服务实例的装饰器该怎么测试?
    最近在网关层开发中频繁用到装饰器,希望能得到一些实战经验指导。
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. 装饰器应用场景

  1. 权限控制:创建@AdminOnly@Public等装饰器
  2. 日志记录:自动记录方法调用
  3. 缓存控制:自动缓存响应
  4. 参数转换:自动转换传入参数格式
  5. 响应处理:统一响应格式

6. 最佳实践

  • 保持装饰器职责单一
  • 为装饰器提供清晰的文档
  • 考虑装饰器的执行顺序
  • 避免过度使用装饰器

定制化装饰器可以显著提高代码的可读性和可维护性,是NestJS开发中非常强大的工具。

回到顶部