中间件
定义中间件
bwcx 支持装载 Koa 式的中间件。要定义一个中间件,需要实现自定义中间件类。
import { MiddlewareNext, RequestContext, IBwcxMiddleware, Middleware } from 'bwcx-ljsm';
@Middleware()
export default class LogMiddleware implements IBwcxMiddleware {
async use(ctx: RequestContext, next: MiddlewareNext) {
const _start = Date.now();
try {
await next();
} finally {
console.log(`[${ctx.method} ${ctx.url} ${ctx.status}](${Date.now() - _start}ms)`);
}
}
}
这里我们实现了一个打印请求日志的中间件类,其必须用 @Middleware()
标注以被容器管理。同样地,如有需要,我们可以在类中注入其他依赖。
TIP
@Middleware()
默认作用域是 DeferredTransient
。
使用全局中间件
如果想把中间件应用到全局,可以在 app.ts
中声明需要应用的中间件。
import LogMiddleware from './middlewares/log.middleware';
class OurApp extends App {
protected globalMiddlewares = [LogMiddleware];
}
在控制器中使用中间件
如果想灵活地应用中间件,可以使用 @UseMiddlewares()
装饰器,它可以装饰控制器或路由方法,接收一个或多个中间件类参数并按顺序加载它们。
import { Inject } from 'bwcx-core';
import { Controller, Get, UseMiddlewares } from 'bwcx-ljsm';
import LogMiddleware from '../middlewares/log.middleware';
@Controller('/user')
@UseMiddlewares(LogMiddleware)
export default class UserController {
@Get('/get')
// 或只给指定路由方法应用中间件
@UseMiddlewares(LogMiddleware)
async getUsers() {
return { rows: [] };
}
}
带参中间件
有时我们需要对中间件使用某些参数初始化或定制行为,类似于中间件工厂。框架提供了带参中间件支持,可以在在装饰位置赋予中间件参数。
首先需要为中间件引入 Reflector,它可以帮助我们读取被装饰类或方法的元数据。这里我们以一个上报中间件为例,需要为接口进行上报,但每个接口要上报的 id 可能不同。
import { Optional } from 'bwcx-core';
import { combineDecorators } from 'bwcx-common';
import { MiddlewareNext, RequestContext, IBwcxMiddleware, Middleware, InjectReflector, Reflector, SetMetadata } from 'bwcx-ljsm';
@Middleware()
export default class ReportMiddleware implements IBwcxMiddleware {
@InjectReflector()
@Optional()
reflector?: Reflector;
async use(ctx: RequestContext, next: MiddlewareNext) {
// 读取被装饰类或方法上的元数据作为参数来改变中间件行为
const reportId = this.reflector?.getMetadata<number>('middleware:reportMiddeware:id');
await next();
reportSome(reportId);
}
}
// 为了便于使用,可以创建一个中间件装饰器工厂
export function Report(id: number) {
// 组合多个装饰器成单个装饰器,和手动应用这些装饰器效果一致
return combineDecorators([
// 为被装饰的方法设置元数据,中间件即可读取它
SetMetadata('middleware:reportMiddeware:id', id),
UseMiddlewares(ReportMiddleware),
]);
}
在控制器上使用:
import { Controller, Get } from 'bwcx-ljsm';
import { Report } from '../middlewares/report.middleware'
@Controller('/user')
export default class UserController {
@Get('/get')
@Report(1)
async getUsers() {
return {
rows: [],
};
}
}
TIP
Reflector
仅可用于中间件、守卫和响应处理器。