错误处理(ErrorHandler)

程序在执行过程中总会遇到一些可预测或者不可预测的异常,如果对这些异常不做处理,可能会导致程序的崩溃,所以我们需要对程序的异常进行捕获并做相应的处理。下面介绍下在使用 Uma 进行开发时有哪些方法可以捕获程序的异常。

在方法中 try-catch

在需要的地方进行try-catch是开发语言为我们提供的捕获错误方法,我们将可能出错的代码通过try-catch进行包裹,在catch中对异常进行处理。

import { BaseController } from '@umajs/core'

export default class Index extends BaseController {
  index() {
    try {
      // ......
      return this.json({ code: 100, msg: 'success' })
    } catch (err) {
      // 出现错误时处理
      return this.json({ code: -100, msg: 'error' })
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

使用 Aspect

Uma 提供的 Aspect 中,我们可以通过afterThrowing异常通知around环绕通知来处理异常。

1. afterThrowing

AOP一节中我们介绍了,当方法执行过程中,如果有未被捕获的异常,则会执行afterThrowing通知,所以我们可以通过 Aspect 的 afterThrowing 方法来处理错误。

// ${URSA_ROOT}/aspect/err.aspect.ts
import { IAspect } from '@umajs/core';

export default class Err implements IAspect {
    afterThrowing(err: Error) {
        // 处理错误
        console.error(`发生错误:${err}`);
    }
}

// ${URSA_ROOT}/controller/index.controller.ts
export default class Index extends  BaseController {
    // 添加异常处理切面方法,当index执行出错时会执行afterThrowing
    @Aspect.afterThrowing('err')
    index() {
        throw new Error('error');
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

注意:Aspect 的 afterThrowing 会捕获所修饰方法未被捕获的错误,如果你已经在方法中 try-catch 了,那么 afterThrowing 方法就不会被执行

2. around

AOP一节中我们介绍了,around通知可以决定目标方法是否执行,我们可以在around接收的参数中获取目标方法proceed,那么我们就可以对proceed使用try-catch来捕获目标方法执行过程中产生的异常。

// ${URSA_ROOT}/aspect/index.aspect.ts
import { IAspect, IProceedJoinPoint } from '@umajs/core'

export default class Index implements IAspect {
  async around(proceedPoint: IProceedJoinPoint) {
    const { proceed, args } = proceedPoint

    try {
      await proceed(...args)
    } catch (err) {
      // 处理错误
      console.error(`发生错误:${err}`)
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

使用 plugin-status

plugin-status是 Uma 为了方便用户对 response不同状态码情况和错误进行处理提供的插件。

具体使用方法可以参考插件/Status一章

// status.config.ts
export default {
    // 针对状态码进行处理
    _404(ctx) {
        return ctx.render('404.html');
    }
    // 针对未被捕获错误进行处理
    _error(e: Error, ctx) {
        // ...
    }
}
1
2
3
4
5
6
7
8
9
10
11

三种错误处理方式的使用场景

  • try-catch: 适合对方法单独进行错误处理
  • Aspect: 更具可复用性,可以对多个方法进行错误处理
  • plugin-status: 对整个系统在运行中未被捕获的错误的兜底操作,让系统更健壮,同时除了错误处理外,更多的是对不同状态码的统一处理