如何修改NestJS控制器/class-validator错误消息格式关联对应字段?
如何修改NestJS + class-validator的错误返回格式?
问题背景
当前NestJS结合class-validator返回的错误格式是数组形式的消息:
{ "statusCode": 422, "message": ["Name is required", "Email is required"], "error": "Unprocessable Entity" }
希望改成错误消息与对应属性绑定的键值对格式:
{ "statusCode": 422, "message": { "name": "Name is required", "email": "Email is required" }, "error": "Unprocessable Entity" }
使用的DTO定义如下:
import { IsNotEmpty } from 'class-validator'; export class CreateUserRequestDTO { @IsNotEmpty({ message: 'Name is required' }) name: string; @IsNotEmpty({ message: 'Email is required' }) email: string; }
解决方案:自定义异常过滤器
通过NestJS的自定义异常过滤器拦截ValidationPipe抛出的校验错误,重新格式化返回结构即可实现需求。
1. 编写自定义异常过滤器
新建validation-exception.filter.ts文件,代码如下:
import { ExceptionFilter, Catch, ArgumentsHost, BadRequestException } from '@nestjs/common'; import { Response } from 'express'; @Catch(BadRequestException) export class ValidationExceptionFilter implements ExceptionFilter { catch(exception: BadRequestException, host: ArgumentsHost) { const ctx = host.switchToHttp(); const response = ctx.getResponse<Response>(); const status = exception.getStatus(); const errorData = exception.getResponse() as { message: Array<{ property: string; constraints: Record<string, string> }>; error: string }; // 把数组格式的错误转换为键值对 const formattedMessage = errorData.message.reduce((result, errorItem) => { // 取第一个约束对应的错误消息(如果有多个校验规则,可根据需求调整) result[errorItem.property] = Object.values(errorItem.constraints)[0]; return result; }, {} as Record<string, string>); response.status(status).json({ statusCode: status, message: formattedMessage, error: errorData.error, }); } }
2. 配置全局ValidationPipe和过滤器
在main.ts中全局配置ValidationPipe,让它返回包含属性详情的错误结构,同时注册自定义过滤器:
import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { ValidationPipe, BadRequestException } from '@nestjs/common'; import { ValidationExceptionFilter } from './validation-exception.filter'; async function bootstrap() { const app = await NestFactory.create(AppModule); // 配置ValidationPipe,让错误携带属性和约束信息 app.useGlobalPipes(new ValidationPipe({ transform: true, exceptionFactory: (errors) => { // 格式化原始错误,保留属性和约束信息 const formattedErrors = errors.map(err => ({ property: err.property, constraints: err.constraints, })); return new BadRequestException({ message: formattedErrors, error: 'Unprocessable Entity', }); }, })); // 注册全局异常过滤器 app.useGlobalFilters(new ValidationExceptionFilter()); await app.listen(3000); } bootstrap();
3. 局部使用过滤器(可选)
如果不需要全局生效,也可以在单个控制器或路由上通过装饰器启用过滤器:
import { Controller, Post, UseFilters, Body } from '@nestjs/common'; import { CreateUserRequestDTO } from './create-user.request.dto'; import { ValidationExceptionFilter } from './validation-exception.filter'; @Controller('users') @UseFilters(ValidationExceptionFilter) // 控制器级生效 export class UsersController { @Post() // @UseFilters(ValidationExceptionFilter) // 路由级生效 create(@Body() dto: CreateUserRequestDTO) { // 业务逻辑 } }
验证效果
当请求不符合DTO校验规则时,接口会返回预期的格式:
{ "statusCode": 422, "message": { "name": "Name is required", "email": "Email is required" }, "error": "Unprocessable Entity" }
内容的提问来源于stack exchange,提问作者user3788133
相关产品推荐
相关产品推荐

