Nestjs中class-validator的@MaxDate装饰器未按预期生效问题
问题原因
- 固定校验日期问题:你给
@MaxDate装饰器直接传入new Date(),该表达式会在服务启动、代码模块加载阶段就执行,生成的是服务启动时刻的固定日期,而非每次请求校验时的实时当前时间。你报错信息里的2021年11月1日就是你服务的启动时间,后续所有请求都会用这个过期的固定日期校验,自然会触发错误。 - 校验装饰器不匹配:
@IsDateString()的作用是校验入参为符合格式的日期字符串,而@MaxDate只能对Date类型的值生效。你没有配置自动类型转换的前提下,入参的日期字符串不会被转为Date对象,会导致@MaxDate校验逻辑异常。
解决步骤
- 首先开启NestJS全局ValidationPipe的自动类型转换能力,在项目入口
main.ts中做如下配置:
import { ValidationPipe } from '@nestjs/common'; import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); // 开启transform参数,自动将入参转为Dto定义的类型 app.useGlobalPipes(new ValidationPipe({ transform: true })); await app.listen(3000); } bootstrap();
- 修改
CreateUserDto代码:
如果你使用的class-validator版本 >= 0.14.0,可以直接传入函数动态生成当前校验时间,配合类型转换装饰器使用:
import { IsString, IsDate, MaxDate } from 'class-validator'; import { Type } from 'class-transformer'; export class CreateUserDto { @IsString() readonly username: string; @IsDate() // 将请求传入的日期字符串自动转为Date对象 @Type(() => Date) // 每次校验时动态生成当前时间作为最大值 @MaxDate(() => new Date(), { message: '出生日期不能晚于当前时间' }) readonly dateofbirth: Date; }
如果你的class-validator版本较低,不支持给@MaxDate传入函数,可以自定义校验装饰器实现动态校验:
// 自定义校验装饰器文件,比如src/common/decorators/max-date-now.decorator.ts import { registerDecorator, ValidationOptions, ValidationArguments } from 'class-validator'; export function MaxDateNow(validationOptions?: ValidationOptions) { return function (object: Object, propertyName: string) { registerDecorator({ name: 'MaxDateNow', target: object.constructor, propertyName: propertyName, options: validationOptions, validator: { validate(value: any, args: ValidationArguments) { return value instanceof Date && value.getTime() < Date.now(); }, defaultMessage(args: ValidationArguments) { return '出生日期不能晚于当前时间'; } }, }); }; }
在Dto中替换原有@MaxDate装饰器即可:
import { IsString, IsDate } from 'class-validator'; import { Type } from 'class-transformer'; import { MaxDateNow } from 'src/common/decorators/max-date-now.decorator'; export class CreateUserDto { @IsString() readonly username: string; @IsDate() @Type(() => Date) @MaxDateNow() readonly dateofbirth: Date; }
内容的提问来源于stack exchange,提问作者Jose Gaspar
相关产品推荐
相关产品推荐

