NestJS验证响应未显示属性名问题求助
在NestJS中给验证响应添加字段名
方法一:通过ValidationPipe的exceptionFactory直接格式化(简单快捷)
这种方法无需额外编写过滤器,直接在ValidationPipe配置中自定义异常内容,适合不需要自定义字段显示名的场景。
修改全局ValidationPipe配置,添加exceptionFactory选项:
import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { ValidationPipe, UnprocessableEntityException } from '@nestjs/common'; import { ValidationError } from 'class-validator'; async function bootstrap() { const app = await NestFactory.create(AppModule); app.useGlobalPipes( new ValidationPipe({ errorHttpStatusCode: 422, forbidUnknownValues: true, transform: true, whitelist: true, validationError: { target: true, // 开启以获取字段名 value: false, // 可选,关闭则不返回字段值 }, // 自定义异常响应格式 exceptionFactory: (validationErrors: ValidationError[] = []) => { const formattedMessages = validationErrors.map(error => { // 获取字段对应的错误消息(取第一个约束错误) const errorMsg = Object.values(error.constraints)[0]; // 拼接字段名和消息 return `${error.property}: ${errorMsg}`; }); return new UnprocessableEntityException({ statusCode: 422, message: formattedMessages, error: 'Unprocessable Entity', }); }, }), ); await app.listen(3000); } bootstrap();
配置后,你会收到类似这样的响应:
{ "statusCode": 422, "message": [ "username: Uesrname is required", "firstName: First Name is required" ], "error": "Unprocessable Entity" }
方法二:自定义全局异常过滤器(支持自定义字段显示名)
如果需要将字段名替换为更友好的名称(比如把firstName显示为First Name),可以用自定义异常过滤器结合元数据实现。
步骤1:创建字段名装饰器
定义一个装饰器,用来给DTO的字段标记友好显示名:
// src/common/decorators/field-name.decorator.ts import { SetMetadata } from '@nestjs/common'; export const FieldName = (name: string) => SetMetadata('fieldName', name);
步骤2:在DTO中使用装饰器
在验证DTO里,给字段加上@FieldName装饰器:
// src/user/dto/create-user.dto.ts import { IsNotEmpty } from 'class-validator'; import { FieldName } from '../../common/decorators/field-name.decorator'; export class CreateUserDto { @FieldName('Username') @IsNotEmpty({ message: 'is required' }) username: string; @FieldName('First Name') @IsNotEmpty({ message: 'is required' }) firstName: string; }
步骤3:创建全局异常过滤器
编写过滤器捕获验证异常,读取元数据并格式化响应:
// src/common/filters/validation-exception.filter.ts import { ExceptionFilter, Catch, ArgumentsHost, UnprocessableEntityException } from '@nestjs/common'; import { ValidationError } from 'class-validator'; import { Reflector } from '@nestjs/core'; import { Response } from 'express'; @Catch(UnprocessableEntityException) export class ValidationExceptionFilter implements ExceptionFilter { constructor(private reflector: Reflector) {} catch(exception: UnprocessableEntityException, host: ArgumentsHost) { const ctx = host.switchToHttp(); const response = ctx.getResponse<Response>(); const status = exception.getStatus(); const errorData = exception.getResponse() as { message: ValidationError[] | string[] }; // 处理验证错误数组 if (Array.isArray(errorData.message) && errorData.message[0] instanceof ValidationError) { const formattedMessages = (errorData.message as ValidationError[]).map(error => { // 读取自定义字段名,没有则用属性名 const displayName = this.reflector.get<string>('fieldName', error.target.constructor.prototype[error.property]) || error.property; const errorMsg = Object.values(error.constraints)[0]; return `${displayName} ${errorMsg}`; }); response.status(status).json({ statusCode: status, message: formattedMessages, error: 'Unprocessable Entity', }); } else { // 非验证错误按原响应返回 response.status(status).json(exception.getResponse()); } } }
步骤4:注册过滤器和ValidationPipe
在main.ts中注册全局过滤器和ValidationPipe:
import { NestFactory, Reflector } from '@nestjs/core'; import { AppModule } from './app.module'; import { ValidationPipe } from '@nestjs/common'; import { ValidationExceptionFilter } from './common/filters/validation-exception.filter'; async function bootstrap() { const app = await NestFactory.create(AppModule); const reflector = app.get(Reflector); app.useGlobalPipes( new ValidationPipe({ errorHttpStatusCode: 422, forbidUnknownValues: true, transform: true, whitelist: true, validationError: { target: true, // 必须开启才能读取DTO的元数据 value: false, }, }), ); // 注册全局异常过滤器 app.useGlobalFilters(new ValidationExceptionFilter(reflector)); await app.listen(3000); } bootstrap();
配置完成后,你会收到符合预期的响应:
{ "statusCode": 422, "message": [ "Username is required", "First Name is required" ], "error": "Unprocessable Entity" }
内容的提问来源于stack exchange,提问作者Hasibur Rahman
相关产品推荐
相关产品推荐

