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

如何在Express中正确实现MongoDB错误处理?最佳实践探讨

问题描述

我拥有一个简易的用户仓库,创建用户时使用try-catch块捕获唯一约束错误并抛出BadRequestError,后续由全局处理器返回对应响应;未知错误则通过process.exit(1)使应用崩溃。但每个数据库查询都添加try-catch并检查错误码既重复又易遗漏;若省略try-catch在中间件处理,又会暴露MongoDB底层错误。现咨询三个问题:

  1. 每次执行数据库查询都需使用try-catch吗?
  2. 是否应在此处检测具体错误类型(如重复字段错误),仓库中该如何处理已知与未知错误?
  3. 遇到未知错误时是否应崩溃应用?例如将ascending设为2会触发错误,崩溃应用是否合适,还是返回500状态码并保持运行?

相关代码如下:

@Service()
export class UserRepository {

  async getAllSorted(ascending: boolean): Promise<UserDto[]> {
    let sort = {};
    sort = { createdAt: ascending ? 1 : -1 };
    const users = await User.find({}).sort(sort);
    return users.map(toUserDto);
  };

  async create(user: UserCreateDto): Promise<UserDto> {
    const newUser = new User(user);
    try {
      const createdUser = await newUser.save();
      return toUserDto(createdUser);
    } catch (error) {
      if (error.code === 11000) { // duplicate field error
        console.error(error);
        throw new BadRequestError('Unique constraint failed while creating the user.', error.keyValue);
      } else {
        throw error;
      }
    }
  }
}

我深知当前应用简单,但希望学习最佳实践,感谢解答。

解答

1. 每次执行数据库查询都需使用try-catch吗?

不需要每个查询都单独写try-catch,这种做法会导致代码冗余且容易遗漏。更高效的方式是在业务层或全局中间件统一捕获异步错误,比如在NestJS中使用全局异常过滤器,或者在控制器层用try-catch包裹业务方法的调用。

不过仓库层可以针对特定操作的已知错误(比如创建用户时的唯一约束冲突)做针对性捕获转换,其他通用查询的错误交给上层统一处理,避免重复代码。

2. 是否应在此处检测具体错误类型,仓库中该如何处理已知与未知错误?

  • 已知错误(如唯一约束冲突11000):应该在仓库层检测并转换为业务相关的自定义错误(比如BadRequestError)。仓库层最清楚数据库操作可能触发的特定错误,在这里转换能让上层业务逻辑不用关心数据库底层的错误码,只处理带有业务语义的错误。
  • 未知错误:仓库层不需要处理,直接抛出即可。上层的全局异常过滤器会统一捕获这些错误,转换为通用的500响应,同时过滤掉MongoDB的底层细节(比如错误栈、数据库结构信息),避免暴露敏感内容。

可以把数据库错误的转换逻辑封装成工具函数,减少重复代码:

function transformDbError(error: any): never {
  if (error.code === 11000) {
    throw new BadRequestError('Unique constraint failed', error.keyValue);
  }
  // 可扩展添加其他已知数据库错误的转换逻辑
  throw error;
}

// 在create方法中复用
async create(user: UserCreateDto): Promise<UserDto> {
  const newUser = new User(user);
  try {
    const createdUser = await newUser.save();
    return toUserDto(createdUser);
  } catch (error) {
    transformDbError(error);
  }
}

3. 遇到未知错误时是否应崩溃应用?

不建议直接用process.exit(1)让应用崩溃,除非是不可恢复的致命错误(比如数据库连接完全断开且无法重连)。

像你提到的把ascending设为2触发的错误,属于参数验证不严谨导致的数据库操作错误,这类错误应该:

  1. 先在控制器或DTO层做参数校验(比如用class-validator限制ascending只能是boolean类型),从源头避免错误;
  2. 如果还是触发了未知错误,全局异常过滤器捕获后返回500 Internal Server Error响应,同时记录详细的错误日志(供排查),保持应用继续运行。

应用崩溃会导致所有正在处理的请求失败,严重影响用户体验,而大多数未知错误是临时或局部的,保持应用运行可以继续处理其他请求。只有当错误会导致数据不一致或应用完全无法提供服务时,才考虑终止应用。

内容的提问来源于stack exchange,提问作者Fatih Yıldız

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 13:16:11