Appearance
NestJS-classvalidator验证
1、认识安装
NestJS 中,class-validator
是一个用于数据验证的库,可以和 NestJS 的管道(Pipes)结合使用,对传入请求的 DTO(数据传输对象)进行验证。确保请求体、查询参数、路由参数等数据是我们想要的东西,例如(手机号码的输入必须是一个有效的手机号码验证)
👉安装 class-validator
和 class-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个字符"
}