如何统一封装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
相关产品推荐
相关产品推荐

