请求正文中的布尔参数在 NestJS api 中始终为真

Posted

技术标签:

【中文标题】请求正文中的布尔参数在 NestJS api 中始终为真【英文标题】:Boolean parameter in request body is always true in NestJS api 【发布时间】:2020-03-21 14:50:16 【问题描述】:

在我的 API 中考虑这个端点:

@Post('/convert')
  @UseInterceptors(FileInterceptor('image'))
  convert(
    @UploadedFile() image: any,
    @Body(
      new ValidationPipe(
        validationError: 
          target: false,
        ,
        // this is set to true so the validator will return a class-based payload
        transform: true,
        // this is set because the validator needs a tranformed payload into a class-based
        // object, otherwise nothing will be validated
        transformOptions:  enableImplicitConversion: true ,
      ),
    )
    parameters: Parameters,
  ) 
    return this.converterService.start(image, parameters);
  

请求的主体,设置为parameters 参数,包含一个名为laserMode 的属性,它应该是一个布尔类型,它在parameters DTO上像这样进行验证:

  @IsDefined()
  @IsBoolean()
  public laserMode: boolean;

现在奇怪的是,当从 PostMan 发送请求时:

    laserMode = false laserMode = cool(布尔值以外的字符串)

我注意到laserMode 总是设置为 true,这是在验证过程完成之后,因为当我 console.log 构造函数中的 Parameter 实例班级的

export class Parameters 
  ...
  constructor() 
    console.log('this :', this);
  
  ...

我没有看到该属性!

注意:当laserMode从请求中移除时,会返回预期的验证错误(应该定义,应该是布尔值)。

// the logged instance 'this' in the constructor
this : Parameters 
  toolDiameter: 1,
  sensitivity: 0.95,
  scaleAxes: 200,
  deepStep: -1,
  whiteZ: 0,
  blackZ: -2,
  safeZ: 2,
  workFeedRate: 3000,
  idleFeedRate: 1200,
  laserPowerOn: 'M04',
  laserPowerOff: 'M05',
  invest: Invest  x: false, y: true 

// the logged laserMode value in the endpoint handler in the controller
parameters.laserMode in controller : true
// the logged laser value from the service
parameters.laserMode in service : true
检查拼写错误 使用 Vue 应用程序而不是邮递员时会发现相同的结果。 所以!!?

【问题讨论】:

【参考方案1】:

这就是我在设法保持布尔类型的同时解决问题的方法。

通过键引用原始对象而不是使用解构值。

import  Transform  from 'class-transformer';

const ToBoolean = () => 
  const toPlain = Transform(
    ( value ) => 
      return value;
    ,
    
      toPlainOnly: true,
    
  );
  const toClass = (target: any, key: string) => 
    return Transform(
      ( obj ) => 
        return valueToBoolean(obj[key]);
      ,
      
        toClassOnly: true,
      
    )(target, key);
  ;
  return function (target: any, key: string) 
    toPlain(target, key);
    toClass(target, key);
  ;
;

const valueToBoolean = (value: any) => 
  if (value === null || value === undefined) 
    return undefined;
  
  if (typeof value === 'boolean') 
    return value;
  
  if (['true', 'on', 'yes', '1'].includes(value.toLowerCase())) 
    return true;
  
  if (['false', 'off', 'no', '0'].includes(value.toLowerCase())) 
    return false;
  
  return undefined;
;

export  ToBoolean ;
export class SomeClass 
  @ToBoolean()
  isSomething : boolean;

【讨论】:

不确定您使用的是哪个版本的Transform,我不得不将其稍微更改为: const toPlain = Transform( (value) => return value; , toPlainOnly: true, ); const toClass = (target: any, key: string) => return Transform( (value) => return valueToBoolean(value); , toClassOnly: true, )(target, key); ;返回函数(目标:任意,键:字符串) toPlain(目标,键); toClass(目标,键); ; ; 你们用的是什么版本?我在 v0.4.0 上。你试过FoosMaster的建议吗?您的版本转换功能的文档应该让您知道您可以访问什么。就我而言,我确实可以访问原始对象和对象中的属性,这就是它起作用的原因。您可以使用 obj[key] 引用该值 github.com/typestack/class-transformer#advanced-usage【参考方案2】:

这是由于选项enableImplicitConversion。显然,所有字符串值都被解释为true,甚至字符串'false'

有一个issue 请求更改class-transformer 的行为。

【讨论】:

好的,但没有它,所有 DTO 属性规则的验证都会失败。我应该转换为字符串而不是布尔值吗? 您可以改用@Transform 注释来控制转换,参见例如***.com/a/55480830/4694994 感谢您的回答,但我将属性转换为字符串而不是布尔值,从而避免了很多麻烦。【参考方案3】:

找到了解决类转换器问题的解决方法

你可以用这个:

@IsBoolean()
@Transform(( value ) => value === 'true')
public laserMode: boolean;

这会将字符串转换为布尔值,基于它是“真”还是任何其他字符串。一个简单的解决方法,但每个字符串都与 true 不同,结果为 false。

【讨论】:

以上是关于请求正文中的布尔参数在 NestJS api 中始终为真的主要内容,如果未能解决你的问题,请参考以下文章

REST API 最佳实践:查询字符串中的参数与请求正文中的参数

NestJs - 如何在拦截器上获取请求正文

Azure 数据工厂 - 尝试将参数添加到 REST API 请求正文中的动态内容

如何在 NestJS 控制器处理程序的请求中获取“已验证的正文”和“已验证的用户”?

Nestjs - 除了Param Decorator,还有另一种获取请求/正文的方法吗?

如何将用户输入的值传递到 c# 中的请求参数正文中?