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

Nestjs自定义参数装饰器未触发,如何实现属性自动注入?

问题原因分析
  • NestJS 原生参数装饰器仅会对被 @Controller 装饰类下的路由处理方法生效,如果你将 @InjectTenant 写在了 Service 层的方法参数上,装饰器逻辑完全不会被触发
  • 你当前的装饰器逻辑直接新建了 CreateAssetDto 实例,会覆盖请求端传入的 assetName 等业务字段,不符合实际使用需求
修复方案

第一步:调整装饰器使用位置

将 @InjectTenant 从 Service 层的 create 方法移到 Controller 层对应路由的参数上。

第二步:修改装饰器逻辑,复用请求中已解析的 DTO 数据

import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import { plainToInstance } from 'class-transformer';
import { CreateAssetDto } from './dto/create-asset.dto';
import { Tenant } from './entities/tenant.entity';

export const InjectTenant = createParamDecorator(
  (data: unknown, ctx: ExecutionContext) => {
    const request = ctx.switchToHttp().getRequest();
    // 读取请求中已经被全局ValidationPipe解析的原始body数据
    const requestBody = request.body;
    // 转换为CreateAssetDto实例,保留原始请求字段
    const createAssetDto = plainToInstance(CreateAssetDto, requestBody);
    // 注入租户信息,实际场景可从request.user、请求头等位置读取真实租户
    createAssetDto.tenant = new Tenant("JAY");
    return createAssetDto;
  }
);

第三步:Controller层正确使用示例

import { Controller, Post } from '@nestjs/common';
import { AssetService } from './asset.service';
import { CreateAssetDto } from './dto/create-asset.dto';
import { InjectTenant } from './decorators/inject-tenant.decorator';

@Controller('assets')
export class AssetController {
  constructor(private readonly assetService: AssetService) {}

  @Post()
  // 此处直接使用自定义参数装饰器,不需要再加@Body()
  async create(@InjectTenant() createAssetDto: CreateAssetDto) {
    console.log(createAssetDto.tenant); // 可正常拿到注入的租户信息
    return this.assetService.create(createAssetDto);
  }
}

可选优化:全局统一注入,无需替换@Body()

如果需要对所有同类型DTO统一注入租户,不想每个路由都修改参数装饰器,可以用拦截器实现:

import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { plainToInstance } from 'class-transformer';
import { CreateAssetDto } from './dto/create-asset.dto';

@Injectable()
export class TenantInjectInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const request = context.switchToHttp().getRequest();
    // 匹配需要注入租户的路由规则,可自行调整
    if (request.method === 'POST' && request.route.path === '/assets') {
      const createAssetDto = plainToInstance(CreateAssetDto, request.body);
      createAssetDto.tenant = new Tenant("JAY");
      request.body = createAssetDto;
    }
    return next.handle();
  }
}

在路由或者全局注册该拦截器后,仍然可以正常使用原生@Body()参数获取注入后的DTO。

内容的提问来源于stack exchange,提问作者Ramdani Muksin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 20:24:01