You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 14:02:43