Nestjs-如何构造代码以优雅处理错误?

发布于 2025-02-03 19:18:27 字数 1605 浏览 2 评论 0原文

我正在努力处理Nestjs应用程序中的错误,因为我在任何地方都在写尝试/捕捉。我也不确定在服务或解决方案/控制器中丢弃错误,还是在某些拦截器或异常过滤器中捕获并重新捕获它是清洁/最佳实践。还在用fn()。然后编写代码。

这是我的代码的一个示例,其中有许多样板代码处理错误的错误处理。

您将如何更干净和干燥处理错误?

  async validateUser(
    email: string,
    plainTextPassword: string,
  ): Promise<User | null> {
    try {
      const user = await this.usersRepository.findOne({ email });
      if (!user) {
        throw new HttpException(
          "Wrong credentials provided",
          HttpStatus.BAD_REQUEST,
        );
      }

      const isMatch = await this.verifyPassword(
        plainTextPassword,
        user?.password,
      );
      if (isMatch) {
        await this.usersRepository.filter(user);
        return user;
      }
    } catch (err) {
      this.logger.error(err);
      throw new HttpException(
        "Something went wrong",
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
  }

  /** This function is used by the validateUser function
   *  Note: This could be written much much shorter in 1-2 lines...
   */
  async verifyPassword(plainTextPassword: string, hashedPassword: string) {
    try {
      const isMatch = await bcrypt.compare(plainTextPassword, hashedPassword);
      if (!isMatch) {
        throw new HttpException(
          "Wrong credentials provided",
          HttpStatus.BAD_REQUEST,
        );
      }
      return isMatch;
    } catch (err) {
      this.logger.error(err);
      throw new HttpException(
        "Something went wrong",
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
  }

I'm struggling to handle errors in my NestJS app because I'm writing try/catch everywhere. I'm also not sure whether it's cleaner/best practice to throw errors in a service or in the resolver/controller, or catch it and rethrow it in some interceptor or exception filter. Also is writing code with fn().then().catch() cleaner since I seem to be rewriting the same errors a lot when using try/catch.

Here is an example of my code with poor error handling with lots of boilerplate code.

How would you handle the errors more cleanly and DRY?

  async validateUser(
    email: string,
    plainTextPassword: string,
  ): Promise<User | null> {
    try {
      const user = await this.usersRepository.findOne({ email });
      if (!user) {
        throw new HttpException(
          "Wrong credentials provided",
          HttpStatus.BAD_REQUEST,
        );
      }

      const isMatch = await this.verifyPassword(
        plainTextPassword,
        user?.password,
      );
      if (isMatch) {
        await this.usersRepository.filter(user);
        return user;
      }
    } catch (err) {
      this.logger.error(err);
      throw new HttpException(
        "Something went wrong",
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
  }

  /** This function is used by the validateUser function
   *  Note: This could be written much much shorter in 1-2 lines...
   */
  async verifyPassword(plainTextPassword: string, hashedPassword: string) {
    try {
      const isMatch = await bcrypt.compare(plainTextPassword, hashedPassword);
      if (!isMatch) {
        throw new HttpException(
          "Wrong credentials provided",
          HttpStatus.BAD_REQUEST,
        );
      }
      return isMatch;
    } catch (err) {
      this.logger.error(err);
      throw new HttpException(
        "Something went wrong",
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
  }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

那些过往 2025-02-10 19:18:27

以下是一些建议:

  • verifypassword:如果唯一可能的值为true(false,函数抛出时),则返回布尔值的目的没有太大目的。您可以将功能的错误部分移动到验证器中,然后简单地返回密码是否匹配。
  • 在这两个功能中,您都首先提出一个特定的错误,然后捕获并用另一个错误替换。如果有人输入一封没有这种方式的不存在电子邮件,他们将收到内部服务器错误,该错误不会提供有关为什么造成错误的信息。这样,您可以删除两个尝试/捕获条款。
  • 在我的 shobm 意见中,当找不到用户电子邮件时,抛出的400应该是404(找不到),而当密码不匹配时,则应该是403(禁止)。
  • 为了进一步简化,您可以使用Nest的特定异常,而不是httpexception,例如notfoundexceptionforbidDenexceptioninternalSeralSeralSeralSeralSeralSeralSeralSeralSeralSeralSeralSeralRorexception。参见 this
  • 无需投掷internalServererRorexception s,因为Nestjs的默认过滤器将处理任何未透露的错误并亲自抛出500个错误。
  • 如果您有一些要不同的特定错误(主要是特定于图书馆的错误,您可能想通知自己或特别记录它们),则可以实现

Here are some suggestions:

  • verifyPassword: there isn't much purpose in returning a boolean if the only possible value is true (when false, the function throws). You can move the error-throwing part of the function to validateUser and simply return whether the password matches.
  • In both functions, you are first throwing a specific error, then catching it and replacing it with another. In case someone enters an inexistent email they can never find out this way, because they will receive an internal server error that gives no information as to why was the error caused. With this you can remove both try/catch clauses.
  • In my humble opinion, the 400 thrown when the user's email is not found should be a 404 (not found), and the one when the password doesn't match should be a 403 (forbidden).
  • To further simplify, you can use nest's specific exceptions instead of HttpException, such as NotFoundException, ForbiddenException and InternalServerErrorException. See this.
  • There is no need to throw InternalServerErrorExceptions, since NestJS's default filter will handle any uncaught error and throw the 500 himself.
  • In case you have some specific errors you want to handle differently (mostly library-specific errors that you might want to notify yourself about or log them particularly), you can implement custom filters for these errors alone, and handle them however you want, and restrict them to only some modules or use them in your whole app. This way, you don't need to have any error-handling logic in your services/controllers, except very specific cases (when a function throwing is something you'd expect in a normal flow)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文