写点什么

使用 TypeScript 从零搭建自己的 Web 框架:路由映射

作者:RoyLin
  • 2024-04-15
    江西
  • 本文字数:1655 字

    阅读完需:约 5 分钟

使用 TypeScript 从零搭建自己的 Web 框架:路由映射

在构建自己的 Web 框架时,使用装饰器来定义路由是一种非常优雅且强大的方法。通过装饰器,我们可以在控制器类上指定基础路径,并为每个方法定义具体的路由。接着,我们利用 TypeScript 的反射能力,解析这些装饰器提供的路由信息,并将其映射到 Web 服务器上。


在本篇文章中,我们将展示如何使用 @Controller@Get@Post 装饰器来定义路由,并通过反射机制将这些路由映射到 hyper-express Web 服务器上。


一、定义装饰器


首先,我们需要定义 @Controller@Get@Post 装饰器。@Controller 用于标记控制器类,并为其提供一个基础路径。@Get@Post 分别用于标记处理 GET 和 POST 请求的方法。


function Controller(basePath: string) {  return function (target: Function) {    Reflect.defineMetadata('basePath', basePath, target);  };}
function Get(path: string) { return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { const basePath = Reflect.getMetadata('basePath', target.constructor); const fullPath = `${basePath}${path}`; Reflect.defineMetadata('route:get', fullPath, target, propertyKey); };}
function Post(path: string) { return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { const basePath = Reflect.getMetadata('basePath', target.constructor); const fullPath = `${basePath}${path}`; Reflect.defineMetadata('route:post', fullPath, target, propertyKey); };}
复制代码


二、创建控制器类


接下来,我们创建一个控制器类,并使用上面定义的装饰器来定义路由。


@Controller('/api')class MyController {  @Get('/hello')  public async getHello(req: any, res: any) {    res.end('Hello from /api/hello');  }
@Post('/submit') public async postSubmit(req: any, res: any) { res.end('Data submitted to /api/submit'); }}
复制代码


在上面的代码中,MyController 类被 @Controller 装饰器标记,并指定了基础路径 /apigetHello 方法被 @Get 装饰器标记,并指定了路由路径 /hello,因此它的完整路径是 /api/hello。同样地,postSubmit 方法被 @Post 装饰器标记,并指定了路由路径 /submit,完整路径为 /api/submit


三、解析并映射路由


现在,我们需要编写代码来解析控制器类上的路由信息,并将其映射到 hyper-express Web 服务器上。


import { createServer } from 'hyper-express';
const app = createServer();
function mapRoutes(controller: any) { const basePath = Reflect.getMetadata('basePath', controller);
const methods = Object.getOwnPropertyNames(controller.prototype).filter(methodName => methodName !== 'constructor');
methods.forEach(methodName => { const getPath = Reflect.getMetadata('route:get', controller.prototype, methodName); const postPath = Reflect.getMetadata('route:post', controller.prototype, methodName);
if (getPath) { app.get(getPath, controller.prototype[methodName].bind(controller)); }
if (postPath) { app.post(postPath, controller.prototype[methodName].bind(controller)); } });}
// 假设 MyController 已经定义并可用mapRoutes(MyController);
app.listen(3000, () => { console.log('Server started on port 3000');});
复制代码


在上面的代码中,mapRoutes 函数遍历控制器类原型上的所有方法,并检查是否存在 @Get@Post 装饰器定义的路由路径。如果存在,则使用 app.getapp.post 方法将方法映射到相应的路由上。注意,我们使用 bind(controller) 来确保方法中的 this 指向控制器实例。


四、总结


结合前文的文件扫描和自动导入,我们可以轻松的将项目中约定或配置的路径下的控制器文件映射到 Web 服务器的路由系统,并且可以使用 IoC 容器实现依赖注入。


用户头像

RoyLin

关注

不积跬步 无以至千里 2019-09-01 加入

还未添加个人简介

评论

发布
暂无评论
使用 TypeScript 从零搭建自己的 Web 框架:路由映射_typescript_RoyLin_InfoQ写作社区