NestJS -如何构建代码来优雅地处理错误?



我正在努力处理我的NestJS应用程序中的错误,因为我到处都在写try/catch。我也不确定在服务或解析器/控制器中抛出错误是否更干净/最佳实践,或者在某些拦截器或异常过滤器中捕获它并重新抛出它。也是用fn().then().catch()cleaner编写代码,因为我似乎在使用try/catch时重写了很多相同的错误。

这是我的代码的一个例子,错误处理很差,有很多样板代码。

如何更干净利落地处理错误?

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,
);
}
}

以下是一些建议:

  • verifyPassword:如果唯一可能的值为真(当为假时,函数抛出),则返回布尔值没有多大意义。您可以将函数中抛出错误的部分移到validateUser中,并简单地返回密码是否匹配。
  • 在这两个函数中,您首先抛出一个特定的错误,然后捕获它并将其替换为另一个。如果有人输入了一个不存在的电子邮件,他们永远无法通过这种方式发现,因为他们将收到一个内部服务器错误,没有提供有关错误原因的信息。这样你就可以删除try/catch子句。
  • 在我的拙见中,当用户的电子邮件未找到时抛出的400应该是404(未找到),而当密码不匹配时应该是403(禁止)。
  • 为了进一步简化,您可以使用nest的特定异常代替HttpException,例如NotFoundException,ForbiddenExceptionInternalServerErrorException。看到这个。
  • 没有必要抛出InternalServerErrorExceptions,因为NestJS的默认过滤器会处理任何未捕获的错误,并自己抛出500。
  • 如果你有一些特定的错误,你想以不同的方式处理(主要是特定于库的错误,你可能想要通知自己或特别记录它们),你可以为这些错误单独实现自定义过滤器,并按照你想要的方式处理它们,并将它们限制在某些模块或在整个应用程序中使用它们。这样,你不需要在你的服务/控制器中有任何错误处理逻辑。除了非常特殊的情况(当函数抛出是您在正常流程中期望的事情时)

最新更新