【nodejs】让nodejs像后端mvc框架(asp.net mvc)一样处理请求--请求处理函数装饰器注册篇(5/8)【controller+action】
文章目录
前情概要
上篇文章把action的注册讲完了,但是我们的处理函数没有指定可接受的httpmethod,也没有别名上面的。下面我们使用typescript的特性之一装饰器来实现一把这个特性。
在控制器和处理函数的注册篇中有说到的第三,第四个参数就在这里排上用场拉。
SetActionDescriptor(cName, aName, undefined, undefined, _reg_controller_name, cType, aType)//加入缓存
第三个参数[httpMethod] 请求方法类型。默认给undefined,后续再通过扫描action上面的特性标签增加进来
第四个参数 [actionName] 路由action名字。默认给undefined,后续再通过扫描action上面的特性标签增加进来
get,post,actionname的装饰器实现方式
代码非常简单,通过SetActionDescriptor函数对当前的action的某些属性进行重写。
typescript的装饰器目前来说还是一个实验性的功能,依照微软的尿性,应该也没变动了,就算有也是增加新功能新特性。
然后装饰器这玩意和后端语言的比如dotnet的特性(attribute)、java的标注等比较相似。可以给方法增加一些额外的数据等。具体,可查看typescript 装饰器参考文档
import { SetActionDescriptor } from './RouteFactory'; import { ActionParamDescriptor, SetActionParamDescriptor, parameterFromType } from './RouteHandler'; /** * 标记当前方法只接受post请求 * * @export * @returns */ export function post() { return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { SetActionDescriptor(target.constructor.name, propertyKey, 'post') } } /** * 标记当前方法只接受get请求 * * @export * @returns */ export function get() { return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { SetActionDescriptor(target.constructor.name, propertyKey, 'get') } } /** * 重写当前方法的名字,请求使用重写后的名字进行调用 * * @export * @param {string} actionName * @returns */ export function actionName(actionName: string) { return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { SetActionDescriptor(target.constructor.name, propertyKey, undefined, actionName) } }
装饰器使用列子
觉不觉得眼熟?是不是和C#、java里面的特性、标注差不多。
//HostController.ts import { BaseController, get, post, auth, actionName, ViewResult } from "gd-express-basic"; export class HostController extends BaseController { @get() public index() { return this.view("hostIndex", {}); } @auth() @post() @actionName("saveHost") public hostAdd() { return this.view("hostAdd", {}); } }
装饰器的基本原理
HostController.ts 为typescript源文件代码。
HostController.js为使用tsc编译为es6后的代码。
//HostController.js "use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { //decorators 就是我们声明的装饰器返回的处理闭包函数啦 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); //d(target, key, r) ,调用函数,实际上就是return function (target: any, propertyKey: string, descriptor: PropertyDescriptor)调用这里返回的这个function。 else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; Object.defineProperty(exports, "__esModule", { value: true }); const gd_express_basic_1 = require("gd-express-basic"); class HostController extends gd_express_basic_1.BaseController { index() { return this.view("hostIndex", {}); } hostAdd() { return this.view("hostAdd", {}); } } // 1.执行__decorate函数 __decorate([ gd_express_basic_1.get(),//调用我们声明的装饰器,返回要处理函数(闭包) __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", void 0) ], HostController.prototype, "index", null); __decorate([ gd_express_basic_1.auth(), gd_express_basic_1.post(), gd_express_basic_1.actionName("saveHost"), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", void 0) ], HostController.prototype, "hostAdd", null); exports.HostController = HostController; //# sourceMappingURL=HostController.js.map
简单来说就是在源文件加载的时候执行一次__decorate函数,__decorate函数内可以简单理解为调用我们的声明的装饰器函数返回的闭包函数。
到此,我们的controller和action的发现和配置基本上算完成了。
【推荐】国内首个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 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义