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

NestJS如何校验POST请求体类型,拦截不符合DTO结构的非法请求

你遇到的空对象问题是两个核心原因导致的:

  1. 嵌套类型没有用@Type装饰器标记,class-transformer无法将请求体的普通对象转换为对应类实例,ValidationPipe无法识别属性
  2. 嵌套层级的所有可选属性没有加@IsOptional()装饰器,非类类型的interface在运行时会被擦除,校验器无法识别

第一步:确认依赖安装

npm install class-validator class-transformer

第二步:改写DTO定义

所有嵌套结构必须定义为Class(不能用Interface,否则运行时会丢失类型信息),每层属性按需添加校验装饰:

import { IsNumber, IsString, IsOptional, ValidateNested, IsNotEmptyObject } from 'class-validator';
import { Type } from 'class-transformer';

// 替换之前的IDValue interface为Class
export class IDValue {
    @IsString()
    @IsOptional()
    ID: string;

    @IsString()
    @IsOptional()
    Value: string;
}

export class DeliveryInfo {
    @IsString()
    @IsOptional()
    ActualDeliveryDateTime: string;

    @IsString()
    @IsOptional()
    ScheduledDeliveryDateTime: string;
}

export class SalesOrderGeneralInfo {
    @IsOptional()
    @ValidateNested()
    @Type(() => IDValue)
    Branch: IDValue;

    @IsOptional()
    @ValidateNested()
    @Type(() => IDValue)
    InventoryLocation: IDValue;

    @IsOptional()
    @ValidateNested()
    @Type(() => IDValue)
    SalesOrderClassification: IDValue;

    @IsString()
    @IsOptional()
    Reference: string;
}

export class SalesOrderUpdate {
    @IsOptional()
    @ValidateNested()
    @Type(() => DeliveryInfo)
    DeliveryInfo: DeliveryInfo;

    @IsOptional()
    @ValidateNested()
    @Type(() => SalesOrderGeneralInfo)
    SalesOrderGeneralInfo: SalesOrderGeneralInfo;
}

export class SalesOrderUpdateDto {
    @IsNumber()
    ID: number;

    @IsNotEmptyObject()
    @ValidateNested()
    @Type(() => SalesOrderUpdate)
    SalesOrder: SalesOrderUpdate;
}

第三步:调整ValidationPipe配置

添加forbidNonWhitelisted: true参数,只要传入不在DTO定义中的属性就直接抛出400错误,完全满足拦截非法属性的需求:

@Post('/update')
@UsePipes(new ValidationPipe({
  whitelist: true, // 自动剥离不在DTO定义中的白名单属性
  forbidNonWhitelisted: true, // 存在非法属性时直接返回校验失败
  transform: true // 自动将请求体转换为DTO类实例
}))
async salesOrderUpdate(
  @Body() body: SalesOrderUpdateDto,
) {
  return await this.salesOrderService.updateSalesOrder(`${body.ID}`, body.SalesOrder);
}

补充说明

你提到的"指定TS类型后传入不匹配结构也不报错"是TS的运行机制导致的:TS的类型校验只在编译阶段生效,运行时所有类型都会被擦除,NestJS本身不会做运行时的类型校验,必须依赖class-validator这类运行时校验库实现。

以上配置可以完全实现你的需求:

  • 允许传入任意子集的合法属性,哪怕只传SalesOrderGeneralInfo.Branch.Value也可以正常解析
  • 只要传入SalesOrderInsuranceInfo或者其他自定义非法属性,接口会直接返回400校验失败

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 14:06:02