@artusx/plugin-koa
插件基于 koa 封装,默认集成 koa-router,并添加 controller / middleware / http method 等注解能力,完全兼容 koa 生态。
概览
在框架各生命周期执行如下操作:
-
willReady
- 加载 middleware,注册 ArtusX 中间件
- 加载 controller,注册路由以及函数中间件
-
didReady
- 加载 koa-router,挂载插件中注册的路由
- 启动 http 服务:koa.listen(port: number)
当服务接收到请求后,先执行应用自定义声明周期 willReady 中,用户拓展的 koa 中间件(参考进阶章节);请求到达 koa-router,执行 ArtusX,并将结果交给 controller,由具体的 handler 完成最终处理。
配置
配置插件
keys 通过 KOA_KEYS
环境变量传入。
iTerm
const key_keys = process.env.KOA_KEYS?.split(',') ?? ['artusx'];
port 默认配置为 7001,可通过 config 修改。
config.default.ts
export default {
koa: {
port: 7001,
},
artusx: {
// 类中间件支持顺序加载,不配置则按 loader 加载顺序依次执行。
// middlewares: [],
},
};
启用插件
core 插件已默认集成,无需单独配置;如需单独使用,可通过如下方式开启插件。
plugin.ts
export default {
koa: {
enable: true,
package: '@artusx/plugin-koa',
},
};
内置注解
@Middleware
类中间件
ℹ️
类中间件为全局中间件,可通过 config.artusx.middlewares
控制执行顺序,否则根据加载顺序执行。
middleware/limitRate.ts
import { ArtusInjectEnum, Inject } from '@artus/core';
import { ArtusXContext, ArtusXNext, Middleware } from '@artusx/plugin-koa';
import { RateLimiterMemory } from 'rate-limiter-flexible';
const rateLimiterOptions = {
points: 6,
duration: 1,
};
@Middleware({
enable: true,
})
export default class LimitRateMiddleware {
@Inject(ArtusInjectEnum.Config)
config: Record<string, string | number>;
private rateLimiter: RateLimiterMemory;
constructor() {
this.rateLimiter = new RateLimiterMemory(rateLimiterOptions);
}
async use(ctx: ArtusXContext, next: ArtusXNext): Promise<void> {
try {
const rateLimiterRes = await this.rateLimiter.consume(ctx.ip);
ctx.set('Retry-After', `${rateLimiterRes.msBeforeNext / 1000}`);
ctx.set('X-RateLimit-Limit', `${rateLimiterOptions.points}`);
ctx.set('X-RateLimit-Remaining', `${rateLimiterRes.remainingPoints}`);
ctx.set('X-RateLimit-Reset', `${new Date(Date.now() + rateLimiterRes.msBeforeNext)}`);
} catch (rejRes) {
ctx.status = 429;
ctx.body = 'Too Many Requests';
return;
}
await next();
}
}
函数中间件
middleware/traceTime.ts
import { ArtusXContext, ArtusXNext } from '@artusx/plugin-koa';
export default async function traceTime(_ctx: ArtusXContext, next: ArtusXNext): Promise<void> {
console.time('trace');
await next();
console.timeEnd('trace');
}
@Controller
此外插件提供了 web服务的常用注解:
@GET: (path: string)
@PUT: (path: string)
@POST: (path: string)
@HEAD: (path: string)
@PATCH: (path: string)
@DELETE: (path: string)
@OPTIONS: (path: string)
@MW: (middlewares: ArtusXHandler[])
controller/home.ts
import { Controller, GET, POST, MW } from '@artusx/plugin-koa';
import type { ArtusXContext } from '@artusx/plugin-koa';
import traceTime from '../middleware/traceTime';
@Controller()
export default class HomeController {
@MW([traceTime])
@GET('/can-be-get')
@POST('/post')
async home(ctx: ArtusXContext) {
ctx.body = 'Hello World';
}
}
进阶使用
自定义 lifecycle.ts
如内置 koa 无法满足需求,可通过自定义 LifecycleHook ,在应用启动前,对 koa 进行拓展。
lifecycle.ts
import {
Inject,
ArtusInjectEnum,
ArtusApplication,
ApplicationLifecycle,
LifecycleHook,
LifecycleHookUnit,
} from '@artus/core';
import { KoaApplication } from '@artusx/core';
@LifecycleHookUnit()
export default class CustomLifecycle implements ApplicationLifecycle {
@Inject(ArtusInjectEnum.Application)
private readonly app: ArtusApplication;
get koa(): KoaApplication {
return this.app.container.get(KoaApplication);
}
@LifecycleHook()
async didLoad() {}
@LifecycleHook()
public async willReady() {
// extend koa
this.koa.use(async (_ctx, next) => {
// do something
await next();
});
}
}