You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NestJS如何通过自定义装饰器正确获取类名与方法名

问题根因

两个异常的核心原因都是方法装饰器的实现不符合NestJS的运行逻辑:

  • 路由404:NestJS基于reflect-metadata存储路由装饰器(@Post/@Get等)注入的路由路径、请求方法等元数据,若装饰器替换原方法时未迁移这些元数据,框架启动阶段无法识别到对应路由,请求自然返回404。
  • 无法获取正确方法名:若装饰器返回匿名包装函数且未保留原方法名标识、未正确绑定运行时this上下文,就无法读取到当前执行的方法名。
可直接使用的修复版@MethodName装饰器
import 'reflect-metadata';

export function MethodName(): MethodDecorator {
  return (target, propertyKey, descriptor: PropertyDescriptor) => {
    const originalMethod = descriptor.value;
    const currentMethodName = propertyKey as string;

    // 重写方法实现,不替换整个descriptor避免丢失原有属性
    descriptor.value = function (...args: unknown[]) {
      // 运行时给实例挂载方法名,和@ClassName的挂载逻辑对齐
      if (!this.__methodName) {
        this.__methodName = currentMethodName;
      }
      // 透传参数和this上下文,执行原方法
      return originalMethod.apply(this, args);
    };

    // 关键:迁移原方法上所有元数据,保证NestJS等框架能正常读取路由等配置
    const originalMetadataKeys = Reflect.getOwnMetadataKeys(originalMethod);
    originalMetadataKeys.forEach(metadataKey => {
      const metadataValue = Reflect.getOwnMetadata(metadataKey, originalMethod);
      Reflect.defineMetadata(metadataKey, metadataValue, descriptor.value);
    });

    // 保留原方法name属性,兼容其他依赖方法名的逻辑
    Object.defineProperty(descriptor.value, 'name', {
      value: currentMethodName,
      writable: false,
      enumerable: false,
      configurable: true
    });

    return descriptor;
  };
}
使用规范
  • 装饰器顺序必须正确:TS装饰器执行顺序为从下到上、从右到左,必须将@MethodName()放在@Post等路由装饰器的下层(更靠近方法定义的位置),否则无法迁移到路由元数据。正确用法示例:
@ClassName()
@Controller('auth')
export class AuthController {
  // 路由装饰器在上层先执行,注入元数据
  @Post('register')
  // 自定义方法名装饰器在下层,能拿到原方法上的所有路由元数据
  @MethodName()
  async register() {
    // 方法内可正常读取两个属性
    console.log(this.__className, this.__methodName); // 输出: AuthController register
  }
}
  • 包装方法不要用箭头函数,否则会丢失运行时的类实例this指向,导致无法读取__className属性,也会破坏NestJS的依赖注入上下文。
  • 错误日志中可直接拼接两个属性实现位置定位:
async register() {
  try {
    // 业务逻辑
  } catch (error) {
    // 日志输出格式示例: [AuthController.register] 接口请求处理失败
    logger.error(`[${this.__className}.${this.__methodName}] 接口请求处理失败`, error);
    throw error;
  }
}
原有写法的问题说明
  • 路由404:如果之前的实现直接给类原型赋值新函数覆盖原方法,没有迁移path、requestMethod等NestJS路由注册依赖的元数据,框架扫描控制器时会跳过该方法,不会注册对应路由。
  • 方法名获取失败:如果直接返回匿名函数作为新的方法实现,函数默认name属性为空,且未在装饰器闭包中保存声明阶段的方法名propertyKey,运行时就无法拿到正确的方法标识。

内容的提问来源于stack exchange,提问作者Mikhail Filchushkin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.31 00:01:17