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

如何统一封装NestJS中功能相似的自定义参数装饰器

你之前的开关参数方案未生效的核心原因:
createParamDecorator返回的是装饰器工厂函数,你额外套的外层函数参数decodeBody是在你定义PlainBodyDecode时就固定了,无法接收用户使用装饰器时传入的动态参数,且参数传递位置错误,Nest会把用户调用装饰器时传入的参数自动注入到createParamDecorator回调的第一个入参中,不需要在外层定义。

以下是两种可行的实现方案:

方案1:符合你预期的装饰器包装实现

先抽离公共的body获取逻辑,再实现通用转换包装函数,就可以实现你想要的对PlainBody包装得到PlainBodyDecode的用法:

import { createParamDecorator, ExecutionContext, BadRequestException } from '@nestjs/common';
import { rawBody } from 'express'; // 替换为你实际使用的rawBody对应依赖

// 抽离公共的纯文本Body获取逻辑
const getPlainBody = async (ctx: ExecutionContext) => {
  const req = ctx.switchToHttp().getRequest();
  if (!req.readable) throw new BadRequestException('Invalid body');
  return (await rawBody(req)).toString('utf8').trim();
};

// 基础PlainBody装饰器
export const PlainBody = createParamDecorator(async (_, ctx: ExecutionContext) => {
  return getPlainBody(ctx);
});

// 通用装饰器转换包装函数:给现有参数装饰器添加返回值处理逻辑
function withTransform<T>(
  originalDecorator: ReturnType<typeof createParamDecorator>,
  transform: (value: any, ctx: ExecutionContext) => T | Promise<T>
) {
  return createParamDecorator(async (data, ctx: ExecutionContext) => {
    const originalValue = await (originalDecorator as any)(data, ctx);
    return transform(originalValue, ctx);
  })();
}

// 完全符合你预期的写法,包装PlainBody得到解码版本
export const PlainBodyDecode = withTransform(PlainBody, (body) => decode(body));

使用方式和你要求的完全一致:

@Post('decode')
decode(@PlainBodyDecode() data: any): string {
  // 业务逻辑
}

@Post('raw')
raw(@PlainBody() rawBody: string): string {
  // 业务逻辑
}

方案2:单装饰器参数控制(更简洁)

如果不需要太灵活的组合能力,直接用单装饰器加参数开关的方式更简单,代码量更小:

import { createParamDecorator, ExecutionContext, BadRequestException } from '@nestjs/common';
import { rawBody } from 'express';

export const PlainBody = createParamDecorator(async (decodeBody = false, ctx: ExecutionContext) => {
  const req = ctx.switchToHttp().getRequest();
  if (!req.readable) throw new BadRequestException('Invalid body');
  const body = (await rawBody(req)).toString('utf8').trim();
  return decodeBody ? decode(body) : body;
});

// 导出别名,和你原有使用方式兼容
export const PlainBodyDecode = () => PlainBody(true);

使用方式支持两种:

// 用别名直接使用
@Post('decode')
decode(@PlainBodyDecode() data: any): string {
  // 业务逻辑
}

// 动态传参控制是否解码
@Post('dynamic')
dynamic(@PlainBody(true) data: any): string {
  // 业务逻辑
}

@Post('raw')
raw(@PlainBody() rawBody: string): string {
  // 业务逻辑
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 05:45:01