NestJS 中 @Query、@Body 等装饰器引发的思考

最近在看NestJS,发现控制器成员函数参数中可以使用@Query@Body等函数参数装饰器来获取响应的请求数据,如下:

class CatsController {
  @Get()
  findAll(@Query() query, @Req() request: Request): string {
    return request.url;
  }
}

这样写优点很显然,我可以获取我想要的数据,另外不用在乎参数的顺序。对装饰器这一块之前没有过多的深究,平时工作中也没有用过。翻了一下NestJS的源码,发现是利用Reflect实现的,具体的没有细究(我才看了NestJS半天时间),就去看了一下Reflect的知识,然后实现一个简单版的,记录一下。

function argA() {
  return (target, propertyKey, paramsIndex) => {
    Reflect.defineMetadata('argA', paramsIndex, target[propertyKey]);
  };
}

function argB() {
  return (target, propertyKey, paramsIndex) => {
    Reflect.defineMetadata('argB', paramsIndex, target[propertyKey]);
  };
}

class T {
  a(@argA() a) {
    console.log(a);
  }
  b(@argB() b) {
    console.log(b);
  }
  c(@argA() a, @argB() b) {
    console.log(a, b);
  }
  d(@argB() b, @argA() a) {
    console.log(b, a);
  }
}

上面实现了argAargB两个装饰器,分别定义了两个元数据(metaData)用来存储参数位置(paramsIndex),然后声明了一个测试类T,有三个成员方法abcd,每个方法的参数个数或顺序均不同。

然后定义一个执行方法run并执行:

const run = (funcName: string) => {
  const argAIndex = Reflect.getMetadata('argA', new T()[funcName]);
  const argBIndex = Reflect.getMetadata('argB', new T()[funcName]);
  const params: any = [];
  if (argAIndex >= 0) {
    params[argAIndex] = 'argA';
  }
  if (argBIndex >= 0) {
    params[argBIndex] = 'argB';
  }
  new T()[funcName](...params);
};

run('a');
run('b');
run('c');
run('d');

控制台输出结果为:

argA
argB
argA argB
argB argA

可以看到结果和预期相符。

你可能感兴趣的:(NestJS 中 @Query、@Body 等装饰器引发的思考)