【问题标题】:NestJs - Catching MongoDB errors with a custom filter and @Catch(MongoError)NestJs - 使用自定义过滤器和 @Catch(MongoError) 捕获 MongoDB 错误
【发布时间】:2019-06-28 14:35:24
【问题描述】:

我正在使用 NestJS 通过 MongoDB 创建自定义 API。我有以下设置:

  // users.controller.ts

  @Post('sign-up')
  @UseFilters(MongoExceptionFilter)
  async signUp(@Body() createUserDto: CreateUserDto): Promise<any> {
    return await this.userService.signUp(createUserDto).catch(error => {
      throw new BadRequestException(error);
    });
  }
  // user.service.ts

  async signUp(createUserDto: CreateUserDto): Promise<User> {
  const createUser = new this.userModel(createUserDto);
    return await createUser.save();
  }
  // mongo-exception.filter.ts

  import { ArgumentsHost,Catch, ConflictException, ExceptionFilter } from '@nestjs/common';
  import { MongoError } from 'mongodb';

  @Catch(MongoError)
  export class MongoExceptionFilter implements ExceptionFilter {
    catch(exception: MongoError, host: ArgumentsHost) {
      console.log('>>>>>>>>>>>>>>>>>>>> exception: ', exception);
    }
  }
  // package.json
  "dependencies": {
    "@nestjs/common": "^5.4.0",
    "@nestjs/core": "^5.4.0",
    "@nestjs/jwt": "^0.2.1",
    "@nestjs/mongoose": "^5.2.2",
    "@nestjs/passport": "^5.1.0",
    "@nestjs/typeorm": "^5.2.2",
    "fancy-log": "^1.3.3",
    "mongoose": "^5.4.7",
    "nestjs-config": "^1.3.0",
    "passport": "^0.4.0",
    "passport-http-bearer": "^1.0.1",
    "passport-jwt": "^4.0.0",
    "reflect-metadata": "^0.1.12",
    "rimraf": "^2.6.2",
    "rxjs": "^6.2.2",
    "typeorm": "^0.2.12",
    "typescript": "^3.0.1",
    "util": "^0.11.1"
  },

现在,每当我对 /sign-up 路由进行 POST 调用时,都应该在 user.service.ts 中调用 save()。这一切都有效。接下来,当我再次发布 /sign-up 路由时,它应该触发 MongoDB 错误,因为具有相同电子邮件地址的用户已经存在(电子邮件地址是唯一的,因此密钥重复)。当我在.catch(err =&gt; ...); 中记录错误时,我看到错误被抛出,但问题是自定义MongoExceptionFilter。我不会触发 MongoError。当我将 @Catch() 留空时,它会触发但无法处理异常。

我做错了什么?由于我看到this 的帖子并将其用作基础,我似乎无法让它发挥作用。是 Mongoose 还是 NestJS 的更新,为什么这不再起作用了?

【问题讨论】:

    标签: javascript node.js mongodb typescript nestjs


    【解决方案1】:

    这是因为您将所有错误都转换为BadRequestExceptions,这样您的MongoExceptionFilter 将不承担任何责任;它检查instanceof MongoError,它为BadRequestException返回false:

    return await this.userService.signUp(createUserDto).catch(error => {
          throw new BadRequestException(error);
        });
    

    这发生在异常过滤器运行之前;他们总是跑到最后。


    从您的控制器中删除 .catch()。如果您真的想将所有其他异常转换为 BadRequestExceptions (400),那么您可以编写第二个异常过滤器,它处理 MongoExceptionFilter 未处理的所有异常:

    @Catch()
    export class BadRequestFilter implements ExceptionFilter {
      catch(exception: Error, host: ArgumentsHost) {
        const response = host.switchToHttp().getResponse();
        response.status(400).json({message: exception.message});
      }
    }
    

    @Catch(MongoError)
    export class MongoFilter implements ExceptionFilter {
      catch(exception: MongoError, host: ArgumentsHost) {
        const response = host.switchToHttp().getResponse();
        if (exception.code === 11000) {
          response.status(400).json({ message: 'User already exists.' });
        } else {
          response.status(500).json({ message: 'Internal error.' });
        }
      }
    }
    

    然后将两者都添加到您的控制器中(顺序很重要!):

    @UseFilters(BadRequestFilter, MongoFilter)
    async signUp(@Body() createUserDto: CreateUserDto): Promise<any> {
    

    【讨论】:

    • 你能给我更多的背景信息吗?所以你的意思是 .catch 不应该在那里?你能举个例子来说明你的意思吗?
    • 是的,您可以删除.catch。 catch 将您的signUp 方法中的任何错误转换为BadRequestException。转换发生在您的 MongoExceptionFilter 因错误而被调用之前。由于它现在是BadRequestException 而不是MongoErrorMongoExceptionFilter 将无法处理它。与其在控制器中将内部错误转换为客户端可以理解的异常(例如 404),不如在您的异常过滤器中执行此操作。
    • 这是因为你不能在异常过滤器中抛出异常,你必须直接创建响应。我在答案中添加了一个示例。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-23
    • 2016-02-01
    • 2016-08-31
    • 2014-03-05
    • 1970-01-01
    • 2021-10-27
    • 1970-01-01
    相关资源
    最近更新 更多