得益于 加入的 decorator 特性,可以使我们跟 Java/C# 一样,更加直观自然的,做面向切面编程。而随着 Type 的成熟,类型系统也让我们增强了信心,面对复杂的业务逻辑,也更有底气。
egg-controller 是集合了一些在 Controller 层开发中常见问题解决方案的插件。
Controller 路由定义
export class HomeController {
@route(\'/api/xxx\', { name: \'获取XXX数据\' })
async getXXX(size: number, page: number) {
return \'homeIndex\';
}
}
可以看到,使用 decorator 的形式来声明 Controller 非常直观,而且方便扩展,添加/修改 Controller 规则直接修改 decorator 的类型定义就好。这种形式也是 Java/C# 的常规操作。
这里的改进除了使用 decorator 替代了 router.js 来进行 Controller 声明以外,还添加了出入参支持,省去了需要手动读写 ctx 的过程,非常直观的声明 Controller 函数的参数需求,以及返回数据类型。
基于 decorator 的写法与之前最大的区别是,在 Controller 这个横切面,之前只有 loader 可以掌控,而现在可以在 decorator 中加以集中控制,再结合 Type 的元信息,可以做出很多扩展,比如:
参数格式化
在 eggjs 中,因为没有类型信息的原因,从 params 和 query 中获取的信息都会是字符串类型,都需要在 Controller 中手动转换。而改造之后的写法,参数直接暴露在函数入参里,我们就可以直接拿写在入参的类型定义作为格式化的依据,根据类型尝试转换,保证参数类型正确,可以初步防止类型不符的参数进入到 Controller,省去手动判断、转换的逻辑。
参数校验
参数格式化只能保证参数的类型一致性,而我们的需求不止这些,比如必选参数为空时需要拦截,有时参数是复杂对象为了防止恶意构造数据,需要对数据格式做深度检测,所以这里引入了参数校验库,parameter,通过它来解决复杂的校验问题。
export class HomeController {
@route(\'/api/xxx\', { name: \'获取XXX数据\', validate Info: [{
name: \'data\',
rule: {
type: \' \',
str: { type: \'string\', max: 20 },
count: { type: \'number\', max: 10, required: false },
},
}] })
async getXXX(data: { str: string, count?: number }>) {
return data.str;
}
}
这里有个问题,在类型是复杂类型时,Type 默认生成的元数据里,类型一律为 ,所以,想要在定义类型的同时,复用类型的定义,只能在编译时做工作,Type 也开放出了编译时插件API,在不用编译时插件的情况下,就需要单独写一份规则的数据。
有插件后:
export class HomeController {
@route(\'/api/xxx\', { name: \'获取XXX数据\' })
async getXXX(data: ValidateRule<{
type: \' \',
rule: {
str: { type: \'string\', max: 20 },
count: { type: \'number\', max: 10, required: false },
},
}>) {
return data.str;
}
}
路由级中间件
函数类型跟 egg 定义稍有不同:
(app: Application, typeInfo: RouteType) => (ctx: any, next: any) => any
egg 已经定义了中间件,为什么在路由上还定义一个?在路由定义的中间件跟全局的中间件区别在于范围,全局中间件更适合大规模的统一处理,用来统一处理特定业务功能接口就大材小用了,还需要设置过滤逻辑,甚至需要在 config 中设置黑白名单。而路由级中间件适合只有部分接口需要的统一处理,配合从 @route 上收集的类型信息处理更佳。
API文档 & 前端SDK
既然已经收集到了那么多元数据,根据这些数据生成API文档就很简单了无非就是前端的展示,也可以把数据转换对接其他的API文档平台。
更近一步,直接生成前端调用SDK?当然没问题。本插件支持通过模板生成,如果没有找到模板,会在SDK生成目录生成默认模板。
// Controller
export class Controller {
@route({ url: \'/ /index\', name: \'首页\' })
async index(id: string, n: number, e: \'enumA\' | \'enumB\', d: Date) {
return \' Index\';
}
}
// 生成代码
export class Service extends {
/** 首页 */
async index(id: string, n: number, e: string, d: Date) {
const __data = { id, n, e, d };
return await this.request({
method: `get`,
url: `/ /index`,
data: __data,
});
}
}
export const Service = new Service();
export default new Service();
开发时
在配置中开启即可,根据需要自定义其他配置。当 Controller 中文件修改时,会同时重新生成对应的前端SDK文件。
构建打包时
在 前端打包流程前 可以使用 egg-controller gensdk 命令生成前端sdk,需要注意,如果为 Type 项目,需要先将 Type 编译,然后执行生成命令。
Controller 作为请求的起点,这只是个开始。
egg 框架
egg-controller 详细文档
继续阅读与本文标签相同的文章
java浅克隆和深克隆的区别详细讲解
-
技术人看《长安十二时辰》的正确姿势是?
2026-05-18栏目: 教程
-
使用logrotate切割日志
2026-05-18栏目: 教程
-
网站漏洞检测 apache nginx解析绕过上传漏洞
2026-05-18栏目: 教程
-
渗透测试 网站安全基础点web讲解(第一点)
2026-05-18栏目: 教程
-
【阿里云新品发布·周刊】第26期:硬核!阿里云新品动态一手掌握
2026-05-18栏目: 教程
