Skip to content

NestJS-classvalidator验证

1、认识安装

NestJS 中,class-validator 是一个用于数据验证的库,可以和 NestJS 的管道(Pipes)结合使用,对传入请求的 DTO(数据传输对象)进行验证。确保请求体、查询参数、路由参数等数据是我们想要的东西,例如(手机号码的输入必须是一个有效的手机号码验证)

👉安装 class-validatorclass-transformer

js
npm install class-validator class-transformer


//或者使用yarn
yarn add  class-validator class-transformer

2、基本使用

👉使用 class-validator 进行验证数据

你可以在 DTO 类中使用 class-validator 提供的装饰器来验证数据的有效性。常用的装饰器包括 @IsString()@IsInt()@IsEmail()@MinLength()@MaxLength() 等。

示例 1: 基本使用

假设我们要实现一个用户注册的 API,需要验证请求体中的数据。

创建 DTO 类

auth/dto 文件夹中创建 register.dto.ts 文件:

js
import { IsString, IsEmail, MinLength, MaxLength, IsNotEmpty } from 'class-validator';
export class RegisterDto {
  @IsString()
  @IsNotEmpty()
  @MinLength(3)
  @MaxLength(20)
  username: string;

  @IsEmail()
  @IsNotEmpty()
  email: string;

  @IsString()
  @IsNotEmpty()
  @MinLength(6)
  password: string;
}

@IsString():验证字段是否为字符串。

@IsNotEmpty():验证字段是否非空。

@MinLength():验证字符串的最小长度。

@MaxLength():验证字符串的最大长度。

@IsEmail():验证字段是否为有效的电子邮件地址。

创建控制器

然后,你可以在控制器中使用这个 DTO:

js
import { Body, Controller, Post } from '@nestjs/common';
import { AuthService } from './auth.service';
import { RegisterDto } from './dto/register.dto';

@Controller('auth')
export class AuthController {
  constructor(private readonly authService: AuthService) {}

  @Post('register')
  async register(@Body() registerDto: RegisterDto) {
    return await this.authService.register(registerDto);
  }
}

启用全局验证

为了让 NestJS 自动启用 class-validator 验证,我们需要在应用程序的主模块中启用全局验证管道。可以通过在 main.ts 中配置 ValidationPipe 来实现。

main.ts 中:

js
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // 启用全局验证管道
  app.useGlobalPipes(new ValidationPipe({
    transform: true,        // 启用自动转换,例如将字符串转换为数字
    whitelist: true,        // 启用白名单功能,自动去除没有在 DTO 中定义的属性
    forbidNonWhitelisted: true, // 启用严格模式,如果请求中包含未定义的字段,则抛出错误
  }));

  await app.listen(3000);
}

bootstrap();

关键配置

transform: true:允许自动转换请求数据类型,例如把字符串 "123" 转换为数字 123

whitelist: true:只允许 DTO 中定义的属性,其它未定义的属性会被自动过滤掉。

forbidNonWhitelisted: true:如果请求数据中包含未在 DTO 中定义的属性,NestJS 会抛出异常。

自定义错误消息

你可以为 class-validator 的验证装饰器添加自定义的错误消息。只需要在装饰器中传入一个字符串即可。

例如:

js
typescriptCopy Codeimport { IsString, IsNotEmpty, MinLength, MaxLength, IsEmail } from 'class-validator';

export class RegisterDto {
  @IsString({ message: '用户名必须是一个字符串' })
  @IsNotEmpty({ message: '用户名不能为空' })
  @MinLength(3, { message: '用户名最小长度为 3' })
  @MaxLength(20, { message: '用户名最大长度为 20' })
  username: string;

  @IsEmail({}, { message: '邮箱格式不正确' })
  @IsNotEmpty({ message: '邮箱不能为空' })
  email: string;

  @IsString({ message: '密码必须是一个字符串' })
  @IsNotEmpty({ message: '密码不能为空' })
  @MinLength(6, { message: '密码最小长度为 6' })
  password: string;
}

启用条件验证

你还可以根据某些条件来启用验证。例如,某个字段的验证只有在另一个字段的值满足特定条件时才会生效。可以使用 @ValidateIf() 装饰器来控制验证的启用。

js
typescriptCopy Codeimport { IsString, IsEmail, IsOptional, ValidateIf } from 'class-validator';

export class RegisterDto {
  @IsString()
  @IsOptional()
  @ValidateIf(o => o.email !== undefined)  // 只有当 email 被定义时,才验证 username
  username: string;

  @IsEmail()
  @IsOptional()
  email: string;
}

创建 DTO 类并使用 class-validator 装饰器进行验证。

在控制器中使用 DTO 来接收请求体。

main.ts 中启用全局验证管道

使用 ValidationPipe 来自动执行验证并处理错误

3、项目使用

👉 创建 DTO 类

在common下面我们建立一个pipes文件夹,里面存放register.dto.ts文件

javascript
import { IsString, IsEmail, MinLength,IsOptional, IsPhoneNumber} from 'class-validator';

// 注册部分规范
export class RegisterDto {
  @MinLength(5)
  username: string;
  
  @MinLength(5)
  password: string;

  @IsOptional() // 可选参数
  @IsString() // 确认密码
  confirmPassword?: string;

  @IsOptional() // 可选参数
  @IsString()
  code?: string;

  @IsOptional() // 可选参数
  @IsString()
  uuid?: string;

  @IsOptional() // 可选参数
  @IsEmail()  // 验证邮箱格式
  email?: string;

  @IsOptional() // 可选参数
  @IsPhoneNumber('CN')  // 验证中国手机号格式
  phone?: string;

}

👉 在控制器auth.controller.ts中使用

javascript
import { RegisterDto } from '@/common/pipes/register.dto';

@Post('register')
register(@Body() registerDto: RegisterDto) {
  return this.authService.register(registerDto);
}

👉 main.ts之中全局引入管道验证

javascript
import { ValidationPipe } from '@nestjs/common';

 // 启用全局验证管道
  app.useGlobalPipes(new ValidationPipe({
    transform: true,
    whitelist: true,
    forbidNonWhitelisted: true,
  }));

👉查看验证信息

这个时候我们已经可以查看到管道给我们返回的验证信息了

javascript
{
    "message": [
        "username must be longer than or equal to 5 characters"
    ],
    "error": "Bad Request",
    "statusCode": 400
}

4、设置调整

👉 设置特定的返回信息

查看信息可以发现这里给我们返回的是英文信息,这里我们如何设置成特定的提示呢

javascript
 @MinLength(5, { message: '账号不能少于5个字符' })
username: string;

👉 设置全局过滤器提示返回信息

这里我们发现每次返回的信息其实都有很多,对于用户很不友好,我们要做的就是提示用户第一条错误信息,这里写一个全局过滤器进行实现

在src下面的common下建立一个filter文件夹,新建一个http-exception.filter.ts文件

javascript
// http-exception.filter.ts

import { ExceptionFilter, Catch, ArgumentsHost } from '@nestjs/common';
import { Response } from 'express';
import { ValidationError } from 'class-validator';

@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
  catch(exception: any, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const status = exception.getStatus();

    // 处理验证错误
    if (exception.response && exception.response.message instanceof Array) {
      const errors = exception.response.message as string[];
      const firstErrorMessage = errors[0]; // 获取第一个错误消息

      response.status(status).json({
        code: status, // 返回状态码
        message: firstErrorMessage,// 返回第一个错误消息
      });
    } else {
      response.status(status).json(exception.response);
    }
  }
}

在全局引入使用

javascript
import { AllExceptionsFilter } from '@/common/filters/http-exception.filter';
// 全局异常过滤器

pp.useGlobalFilters(new AllExceptionsFilter()); // 全局异常过滤器

这个时候查看我们的过滤掉的返回信息已经正常了

javascript
{
    "code": 400,
    "message": "账号不能少于5个字符"
}

Released under the MIT License.