如何在NestJS中全局修改TypeORM默认错误信息?
问题描述
我写了一段代码,用于在TypeORM中处理唯一列值重复的情况(错误码23505),自定义默认错误信息:
if (error.code === '23505') { // 最终消息格式:This COLUMN VALUE already exists. const message = error.detail.replace( /^Key \((.*)\)=\((.*)\) (.*)/, 'The $1 $2 already exists.', ); throw new BadRequestException(message); } throw new InternalServerErrorException();
这段代码需要在多个服务中复用,我原本考虑创建工具类,在需要的地方导入调用,但想知道有没有更好的方案——比如用全局过滤器或拦截器统一处理,不用在每个服务里都导入调用。请问这种全局处理的方式可行吗?如果可行该怎么实现?如果不可行,最优方案是什么?
以下是完整的服务代码示例:
@Injectable() export class MerchantsService { constructor( @InjectRepository(Merchant) private merchantRepository: Repository<Merchant>, ) {} public async create(createMerchantDto: CreateMerchantDto) { try { const user = this.merchantRepository.create({ ...createMerchantDto, documentType: DocumentType.NIT, isActive: false, }); await this.merchantRepository.save(user); const { password, ...merchantData } = createMerchantDto; return { ...merchantData, }; } catch (error) { if (error.code === '23505') { // 最终消息格式:This COLUMN VALUE already exists. const message = error.detail.replace( /^Key \((.*)\)=\((.*)\) (.*)/, 'The $1 $2 already exists.', ); throw new BadRequestException(message); } throw new InternalServerErrorException(); } } public async findOneByEmail(email: string): Promise<Merchant | null> { return this.merchantRepository.findOneBy({ email }); } }
解决方案
一、全局异常过滤器(推荐方案)
完全可行,用NestJS的全局异常过滤器可以统一处理所有TypeORM抛出的23505错误,不用在每个服务里重复写捕获逻辑。
实现步骤:
- 创建全局异常过滤器类
import { ExceptionFilter, Catch, ArgumentsHost } from '@nestjs/common'; import { Response } from 'express'; import { QueryFailedError } from 'typeorm'; @Catch(QueryFailedError) export class UniqueConstraintFilter implements ExceptionFilter { catch(exception: QueryFailedError, host: ArgumentsHost) { const ctx = host.switchToHttp(); const response = ctx.getResponse<Response>(); // 处理PostgreSQL的唯一约束错误(错误码23505) if (exception.code === '23505') { const message = exception.detail.replace( /^Key \((.*)\)=\((.*)\) (.*)/, 'The $1 $2 already exists.', ); response.status(400).json({ statusCode: 400, message: message, error: 'Bad Request' }); } else { // 其他数据库错误,返回500 response.status(500).json({ statusCode: 500, message: 'Internal Server Error', error: 'Internal Server Error' }); } } }
- 在主模块(比如
AppModule)注册全局过滤器
import { Module } from '@nestjs/common'; import { APP_FILTER } from '@nestjs/core'; import { UniqueConstraintFilter } from './filters/unique-constraint.filter'; @Module({ providers: [ { provide: APP_FILTER, useClass: UniqueConstraintFilter, }, ], }) export class AppModule {}
- 移除服务中的重复代码
现在可以删掉每个服务里捕获23505错误的逻辑,直接让异常抛出,过滤器会自动处理。比如你的MerchantsService可以简化成:
@Injectable() export class MerchantsService { constructor( @InjectRepository(Merchant) private merchantRepository: Repository<Merchant>, ) {} public async create(createMerchantDto: CreateMerchantDto) { const user = this.merchantRepository.create({ ...createMerchantDto, documentType: DocumentType.NIT, isActive: false, }); await this.merchantRepository.save(user); const { password, ...merchantData } = createMerchantDto; return { ...merchantData, }; } public async findOneByEmail(email: string): Promise<Merchant | null> { return this.merchantRepository.findOneBy({ email }); } }
二、备选方案:工具函数封装
如果因为某些原因不能用全局过滤器,工具函数是次优选择:
- 创建工具函数
// src/utils/handle-unique-error.ts import { BadRequestException, InternalServerErrorException } from '@nestjs/common'; import { QueryFailedError } from 'typeorm'; export const handleUniqueError = (error: unknown) => { if (error instanceof QueryFailedError && error.code === '23505') { const message = error.detail.replace( /^Key \((.*)\)=\((.*)\) (.*)/, 'The $1 $2 already exists.', ); throw new BadRequestException(message); } throw new InternalServerErrorException(); };
- 在服务中导入使用
import { handleUniqueError } from '../utils/handle-unique-error'; // ...服务代码中 public async create(createMerchantDto: CreateMerchantDto) { try { // ...原有逻辑 } catch (error) { handleUniqueError(error); } }
方案对比
- 全局过滤器:最优,完全解耦,无需在任何服务中重复处理,维护成本最低。
- 工具函数:适合需要对部分错误做特殊处理的场景,但仍需在每个服务的catch块中调用,复用性不如全局过滤器。
内容的提问来源于stack exchange,提问作者Vicente Losada Fadul
相关产品推荐
相关产品推荐

