【nodejs】让nodejs像后端mvc框架(asp.net mvc)一样处理请求--控制器和处理函数的注册篇(4/8)【controller+action】
文章目录
前情概要
前边的文章把一些基本的前置任务都完成了。接下就是比较重要的处理函数action是如何自动发现和注册的拉,也就是入口函数RouteHandler(也是我们的第一个express中间件)里面的一些细节。
扫描action并添加到缓存
说一说我们的思路,其实和静态语言中的反射概念有点类似。
- 循环传进来的所有controller声明。详见 控制器的声明和定义篇---controller注册到RouteHandler
- 循环所有声明的controllers,并将每一个controller里面的action添加到action缓存中。
关键方法也就是Object.getOwnPropertyNames和Object.getOwnPropertyDescriptor2个方法了。目的则是对象上的所有成员,对应到比如说.net,java之类的就是反射拉。
export function RouteHandler(app: core.Express, controllers: any) { find(controllers) //app.use('/', (req, res, next) => 。。。。。。 } function find(controllers: any) { //controllers本质上是一个对象,类似:{host:{},home:{},site:{}}。那我们这里的key就是controller的名字,value就是controller实列了。 var _reg_controller_names = Object.getOwnPropertyNames(controllers)//对象上所有成员,就是我们所有的controller名称集合。 for (var index = 0; index < _reg_controller_names.length; index++) { var _reg_controller_name = _reg_controller_names[index];//controller的名称,比如:home var _reg_controller_Desc = Object.getOwnPropertyDescriptor(controllers, _reg_controller_name) as PropertyDescriptor//controller的描述对象 if (_reg_controller_name === '__esModule') continue; var cType = _reg_controller_Desc.value;//controller的类型,比如:Homecontroller var cName = cType.name;//controller的class名称。比如"HomeController"; var aNames = Object.getOwnPropertyNames(cType.prototype)//controller所有成员,也就是我们的action for (var index2 = 0; index2 < aNames.length; index2++) { var aName = aNames[index2]; if (aName === 'constructor') continue; var aType = (Object.getOwnPropertyDescriptor(cType.prototype, aName) as PropertyDescriptor).value//具体的每一个action函数 SetActionDescriptor(cName, aName, undefined, undefined, _reg_controller_name, cType, aType)//加入缓存 //第三个参数[httpMethod] 请求方法类型。默认给undefined,后续再通过扫描action上面的特性标签增加进来 //第四个参数 [actionName] 路由action名字。默认给undefined,后续再通过扫描action上面的特性标签增加进来 } } }
SetActionDescriptor的实现
/** * * * @export * @param {string} controllerTypeName 控制器类型名字 * @param {string} actionTypeName 方法类型名字 * @param {string} [httpMethod] 请求方法类型 * @param {string} [actionName] 路由action名字 * @param {string} [controllerName] 路由控制器名字 * @param {*} [controllerType] 控制器对象 * @param {*} [actionType] action 对象 * @returns {ActionDescriptor} */ export function SetActionDescriptor(controllerTypeName: string, actionTypeName: string, httpMethod?: string, actionName?: string, controllerName?: string, controllerType?: any, actionType?: any, isAuth?: boolean): ActionDescriptor { var _actions = _dic_override.get(controllerTypeName) if (!_actions) { _actions = new Map<string, ActionDescriptor>(); _dic_override.set(controllerTypeName, _actions) } var _action = _actions.get(actionTypeName); if (!_action) { _action = new ActionDescriptor(); _actions.set(actionTypeName, _action) } _action.ControllerTypeName = controllerTypeName; _action.ActionTypeName = actionTypeName; if (!_action.ActionName) _action.ActionName = actionTypeName if (httpMethod) _action.HttpMethod = httpMethod.toUpperCase(); if (controllerType) _action.ControllerType = controllerType; if (controllerName) _action.ControllerName = controllerName; if (actionName) _action.ActionName = actionName; if (actionType) _action.ActionType = actionType if (isAuth === true || isAuth === false) _action.isAuth = isAuth; _action.Id = _action.ActionName + (_action.HttpMethod ? ('_' + _action.HttpMethod) : '') return _action }
SetActionDescriptor方法参数有值得情况下则更新,没有值则跳过。因为针对同一个action可能会被调用多次。对一个action的描述信息也是分部分分多次set进来的。一部分是通过对象的原型,还有一部分则是ts的装饰器(后端语言的attribute)。
需要注意的是每个action有个id字段。id字段使用http method和action name 来拼接。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义