异常处理
Midway 提供了一个内置的异常处理器,负责处理应用程序中所有未处理的异常。当您的应用程序代码抛出一个异常处理时,该处理器就会捕获该异常,然后等待用户处理。
异常处理器的执行位置处于中间件之后,所以它能拦截所有的中间件和业务抛出的错误。
Http 异常
在 Http 请求中,Midway 提供了通用的 MidwayHttpError
类型的异常,其继承于标准的 MidwayError
。
export class MidwayHttpError extends MidwayError {
// ...
}
我们可以在请求的过程中抛出该错误,由于错误中包含状态码,Http 程序将会自动返回该状态码。
比如,下面的代码,抛出了包含 400 状态码的错误。
import { MidwayHttpError } from '@midwayjs/core';
// ...
async findAll() {
throw new MidwayHttpError('my custom error', HttpStatus.BAD_REQUEST);
}
// got status: 400
但是一般我们很少这么做,大多数的业务的错误都是复用的,错误消息也基本是固定的,为了减少重复定义,我们可以自定义一些异常类型。
比如自定义一个状态码为 400 的 Http 异常,可以如下定义错误。
// src/error/custom.error.ts
import { HttpStatus } from '@midwayjs/core';
export class CustomHttpError extends MidwayHttpError {
constructor() {
super('my custom error', HttpStatus.BAD_REQUEST);
}
}
然后在业务中抛出使用。
import { CustomHttpError } from './error/custom.error';
// ...
async findAll() {
throw new CustomHttpError();
}
异常处理器
内置的异常处理器用于标准的请求响应场景,它可以捕获所有请求中抛出的错误。
通过 @Catch
装饰器我们可以定义某一类异常的处理程序,我们可以轻松的捕获某一类型的错误,做出处理, 也可以捕获全局的错误,返回统一的格式。
同时,框架也提供了一些默认的 Http 错误,放在 httpError
这个对象下。
比如捕获抛出的 InternalServerErrorError
错误。
我们可以将这一类异常处理器放在 filter
目录,比如 src/filter/internal.filter.ts
。
// src/filter/internal.filter.ts
import { Catch, httpError, MidwayHttpError } from '@midwayjs/core';
import { Context } from '@midwayjs/koa';
@Catch(httpError.InternalServerErrorError)
export class InternalServerErrorFilter {
async catch(err: MidwayHttpError, ctx: Context) {
// ...
return 'got 500 error, ' + err.message;
}
}
catch
方法的参数为当前的错误,以及当前应用该异常处理器的上下文 Context
。我们可以简单的将响应的数据返回。
如果不写参数,那么会捕获所有的错误,不管是不是 HttpError,只在要请求中抛出的错误,都会被这里捕获。
// src/filter/all.filter.ts
import { Catch } from '@midwayjs/core';
import { Context } from '@midwayjs/koa';
@Catch()
export class AllErrorFilter {
async catch(err: Error, ctx: Context) {
// ...
}
}
定义的异常处理器只是一段普通的代码,我们还需要将它应用到我们某个框架的 app 中,比如 http 协议的 app。
我们可以在 src/configuration.ts
中将错误处理过滤器应用上,由于参数可以是数组,我们可以应用多个错误处理器。
// src/configuration.ts
import { Configuration, App, Catch } from '@midwayjs/core';
import { join } from 'path';
import * as koa from '@midwayjs/koa';
import { InternalServerErrorFilter } from './filter/internal.filter';
@Configuration({
imports: [
koa
],
})
export class MainConfiguration {
@App()
app: koa.Application;
async onReady() {
this.app.useFilter([InternalServerErrorFilter]);
}
}
注意,某些非 Midway 的中间件或者框架内部设置的状态码,由于未使用错误抛出的形式,所以拦截不到,如果在业务中返回 400 以上的状态,请尽可能使用标准的抛出错误的形式,方便拦截器做处理。
404 处理
框架内部,如果未匹配到路由,会抛出一个 NotFoundError
的异常。通过异常处理器,我们可以自定义其行为。
比如跳转到某个页面,或者返回特定的结果:
// src/filter/notfound.filter.ts
import { Catch, httpError, MidwayHttpError } from '@midwayjs/core';
import { Context } from '@midwayjs/koa';
@Catch(httpError.NotFoundError)
export class NotFoundFilter {
async catch(err: MidwayHttpError, ctx: Context) {
// 404 错误会到这里
ctx.redirect('/404.html');
// 或者直接返回一个内容
return {
message: '404, ' + ctx.path
}
}
}