拦截器(AOP)
我们经常有全局统一处理逻辑的需求,比如统一处理错误,转换格式等等,虽然在 Web 场景有 Web 中间件来处理,但是在其他场景下,无法使用这个能力。
Midway 设计了一套通用的方法拦截器(切面),用于在不同场景中,统一编写逻辑。
拦截器和传统的 Web 中间件和装饰器都不同,是由 Midway 框架提供的能力,在执行顺序上,处于中间的位置,这个能力能对任意的 Class 方法做拦截。

使用拦截器(切面)
拦截器一般会放在 src/aspect 目录。下面我们写一个对控制器(Controller)方法拦截的示例。创建一个 src/aspect/report.ts 文件。
➜ my_midway_app tree
.
├── src
│ │── aspect ## 拦截器目录
│ │ └── report.ts
│ └── controller ## Web Controller 目录
│ └── home.ts
├── test
├── package.json
└── tsconfig.json
// src/controller/home.ts
import { Controller, Get } from '@midwayjs/core';
@Controller('/')
export class HomeController {
@Get('/')
async home() {
return "Hello Midwayjs!";
}
}
内容如下:
import { Aspect, IMethodAspect, JoinPoint } from '@midwayjs/core';
import { HomeController } from '../controller/home';
@Aspect(HomeController)
export class ReportInfo implements IMethodAspect {
async before(point: JoinPoint) {
console.log('before home router run');
}
}
启动项目,运行后,在控制台会输出 before home router run 的字样。
你会发现,我们不需要去侵入控制器的代码,既没有在业务文件中加装饰器,也没有在主流程前后可见的加代码。
拦截器(切面)的能力非常强大,也非常可怕,我们一定要小心而正确的使用。
拦截器 固定为单例。
警告
在继承的情况下,拦截器不会对父类的方法生效。
可切面的生命周期
方法拦截器可以对整个方法进行拦截,拦截的方式包括几个方面。
export interface IMethodAspect {
after?(joinPoint: JoinPoint, result: any, error: Error);
afterReturn?(joinPoint: JoinPoint, result: any): any;
afterThrow?(joinPoint: JoinPoint, error: Error): void;
before?(joinPoint: JoinPoint): void;
around?(joinPoint: JoinPoint): any;
}
| 方法 | 描述 |
|---|---|
| before | 方法调用前执行 |
| around | 包裹方法的前后执行 |
| afterReturn | 正确返回内容时执行 |
| afterThrow | 抛出异常时执行 |
| after | 最后执行(不管正确还是错误) |
简单理解如下;
try {
// before
// around or invokeMethod
// afterReturn
} catch(err){
// afterThrow
} finally {
// after
}
| 修改入参 | 调用原方法 | 获取返回值 | 修改返回值 | 获取错误 | 拦截并抛出错误 | |
|---|---|---|---|---|---|---|
| before | √ | √ | ||||
| around | √ | √ |