我们在开发 Web 应用的时候,处理程序意外情况是十分普遍的事情。在 HTTP 请求的整个处理链路中,当发生错误时,一种处理方式是在错误发生的地方自己捕获直接处理掉;另一种方式是抛出错误,交由上层处理。

错误拦截器

Malagu 框架提供了一种错误处理拦截器机制,通过实现接口 ErrorHandler 提供错误处理器,然后根据优先级将错误处理器排序,当发生错误的时候,错误依次传入错误处理器,直到找到匹配的错误处理器为止。

在错误处理器链的末端,框架提供了一个默认错误处理器,当错误处理器链前面的处理器都无法匹配该错误时,则交由末端默认错误处理器来处理。

通过错误处理拦截器机制,我们可以很容易将错误处理相关的代码与业务代码分离,让业务代码更加专注业务逻辑的编写,同时,我们也可以全局统一处理错误逻辑,从而保证整个应用错误处理风格的一致性。

注意事项

在错误处理器中,我们是通过 instanceof 语法来匹配错误是否由本错误处理器处理,默认 Node.js 提供的 Error 类无法使用 instanceof 语法来匹配,所以推荐使用框架提供 CustomError 基类来实现您自己的错误类。

  1. import { CustomError } from '@malagu/core';
  2. export class HttpError extends CustomError {
  3. constructor(public statusCode: number, message?: string) {
  4. super(message);
  5. }
  6. }

自定义错误处理器

当我们处理自定义错误,或者扩展框架内置的错误处理器时,我们需要实现自定义的错误处理器。首先,实现接口 ErrorHandler ,并将实现类注入到 IoC 容器,注入的 ID 为 ErrorHandler 。当发生错误时,框架通过 ErrorHandler 取到所有的错误处理器,并按优先级排序。如果您想替换掉某个错误处理器,只要确保您实现的优先级大于需要替换的错误处理器即可。

  1. @Component(ErrorHandler)
  2. export class HttpErrorHandler implements ErrorHandler {
  3. readonly priority: number = HTTP_ERROR_HANDlER_PRIORITY;
  4. canHandle(ctx: Context, err: Error): Promise<boolean> {
  5. return Promise.resolve(err instanceof HttpError);
  6. }
  7. async handle(ctx: Context, err: HttpError): Promise<void> {
  8. ctx.response.statusCode = err.statusCode;
  9. ctx.response.end(err.message);
  10. }
  11. }

@Catch

在 mvc 组件中,我们提供了一个装饰器 @Catch() 帮助我们处理控制器当中抛出的异常。异常处理器方法必须定义在控制器当中,与 HTTP 请求处理器相似,不同的是异常处理器方法匹配的是具体的异常。异常处理器有以下规则:

  • 只有控制器里面抛出的异常才会走异常映射流程
  • 异常类必须继承 CustomError 基类,或者您提供的异常对象支持 instanceof 语法
  • @Catch 的使用不需要与抛异常的控制器是同一个
  • 异常控制器方法会继承抛异常的控制器方法的上下文,包括视图、请求的各种属性
  1. @Controller()
  2. export class ErrorController {
  3. @Catch(FooError)
  4. handle(err: FooError, @Body() body) {
  5. ...
  6. }
  7. }

内置错误类

  • CustomError
  • IllegalArgumentError
  • ValidationErrors
  • HttpError
  • NotFoundError
  • NotFoundAndContinueError
  • AuthenticationError
  • AccountStatusError
  • UsernameNotFoundError
  • BadCredentialsError
  • LockedError
  • DisabledError
  • AccountExpiredError
  • AccessDeniedError
  • OAuth2AuthorizationError
  • OAuth2AuthenticationError
  • ClientAuthorizationError
  • ClientAuthorizationRequiredError