从0开发属于自己的nestjs框架的mini 版 —— 终极篇

2023-07-30 18:12:03 来源:博客园


(资料图片仅供参考)

这篇其实是最简单的,就是将前面所实现的ioc,路由整合在一起就可以了

话不多说,直接上代码

\src\koa-ioc.ts

引入相关库

import Koa from "koa";import koaRouter from "koa-router";import { ContainerModule } from "./ioc-module";import { Type } from "./ioc-core.ts";import { ResigerRouter } from "./koa-decorator";

声明类型

/****************声明类型************ *//** * 异常响应类型 */export type IExceptionsFilter = (  ctx: Koa.DefaultContext,  error: Error) => void | any | Promise;/** * 成功响应类型 */export type IResponseInterceptor = (ctx: Koa.DefaultContext) => unknown;/** * 实例参数类型 */interface IKoaNestOption {  koaOption?: ConstructorParameters; // ConstructorParameters获取构造函数参数的类型  prefix?: string;  routerOptions?: koaRouter.IRouterOptions;  [key: string]: any;}

NestFactory 实现的

export class NestFactory {  [x: string]: any;  private iocInstance: ContainerModule; // ioc容器实例  private koaInstance: Koa; // koa 实例  private routerInstance: koaRouter; // 路由实例  private middleWareQuence: Array = []; // 全局中间件  private exceptionsFilterQuence: Array = []; // 全局异常拦截器(中间件)  private responseInterceptorQuence: Array = []; // 全局响应拦截器(中间件)  constructor(appModule: Type, options: IKoaNestOption = {}) {    const { routerOptions = {}, koaOption = {} } = options || {};    this.iocInstance = new ContainerModule(appModule);    this.routerInstance = new koaRouter({      ...routerOptions,      prefix: options.prefix,    });    this.koaInstance = new Koa(koaOption);  }  private init() {    this.appError();    // 加载全局中间件    this.koaInstance.use(this.setFirstMiddleware());    this.middleWareQuence.forEach((middleware: Koa.Middleware) =>      this.koaInstance.use(middleware)    );    // 加载路由    this.loadRoutes();  }  // 设置第一个中间,可以捕获(任何一个中间件异常)全局响应和错误处理  private setFirstMiddleware = () => {    return async (ctx: Koa.DefaultContext, next: Function) => {      try {        ctx.requestId = Math.random();        await next();        this.responseInterceptorQuence.forEach((itme) => itme(ctx));      } catch (error) {        ctx.app.emit("error", error, ctx);      }    };  };  /**   * 加载路由   */  private loadRoutes() {    const ctrInstance = this.iocInstance.getControllerInstance();    ctrInstance.forEach((itme) => ResigerRouter(this.routerInstance, itme));    this.koaInstance.use(this.routerInstance.routes());  }  // 监听错误响应  private appError() {    this.koaInstance.on("error", (error: Error, ctx: Koa.DefaultContext) => {      this.exceptionsFilterQuence.forEach((itme) => itme(ctx, error));    });  }  //添加全局中间件  public use(...middleware: Array) {    this.middleWareQuence = [...this.middleWareQuence, ...middleware];  }  //添加全局异常拦截器  public setGlobalExceptionsFilter(...fn: Array) {    this.exceptionsFilterQuence = [...this.exceptionsFilterQuence, ...fn];  }  // 添加全局响应拦截器  public setGlobalResponseInterceptor(...fn: Array) {    this.responseInterceptorQuence = [...this.responseInterceptorQuence, ...fn];  }  //服务启动  public listen(port: number, host?: string | Function, callback?: Function) {    this.init();    if (typeof host == "function") {      callback = host;      host = "0.0.0.0";    }    this.koaInstance.listen(port, host, callback && callback());  }  public getKoa() {    return this.koaInstance;  }  public getRouter() {    return this.routerInstance;  }}

测试用例

import Koa from "koa";import { Controller, GET, Query, Ctx } from "./koa-decorator";import { NestFactory } from "./koa-ioc";import { Module } from "./ioc-module";import { Injectable, Inject } from "./ioc-core";@Injectable()class UserService {  private data: Array = [];  constructor() {    this.data = [{ id: 1 }, { id: 2 }, { id: 3 }];  }  findUser(id: number) {    return this.data.find((item) => item.id == id);  }}@Controller("user")class UserController {  constructor(private userService: UserService) {}  @GET("list")  getUserId(@Query("id") id: number, @Ctx() ctx: Koa.DefaultContext) {    console.log("ctx", ctx, id);    let result = this.userService.findUser(id);    if (!result) {      throw new Error(`用户id [${id}] 不存在`);    }    return result;  }}@Module({  providers: [UserService],  controllers: [UserController],  imports: [],})class AppModule {}function start() {  const app = new NestFactory(AppModule, { prefix: "/api" });  // 全局响应中间件  app.setGlobalResponseInterceptor(async (ctx) => {    ctx.body = await { data: ctx.body, success: true, status: 200 };  });  // 全局异常捕获中间件  app.setGlobalExceptionsFilter(async (ctx, error) => {    ctx.body = await {      data: null,      success: false,      status: 500,      message: error.message ? error.message : error,    };  });  app.listen(8000, () => {    console.info("app is runing in prot 8080");  });}start();

总结

1、至此,一个mini 版本的nestjs 框架就完成了2、重提一点,这个只是学习,对于使用nestjs 也是有很大帮助的3、在此基础是可以扩展更多的功能,比如类中间件,方法中间件,守卫,管道等等也是可以的4、这个是基础版本,想要更完善的功能学习的,可以参考 npm i @bylive/nestjs 这个增强版的

编辑:

最近更新

每日推荐

努宝状态火热努涅斯后点补射破

努宝状态火热努涅斯后点补射破门,热身赛3场进4球,若塔,努宝,利物浦,莱

中工网带你去追星丨“人刀合一

汽车制造、“人刀合一”、钢铁“雕刻”家——本期《中工网带你去...

虁(关于虁简述)

,你们好,今天0471房产来聊聊一篇,简述的文章,网友们对这件事情都比

王者荣耀gank是指什么意思(王

导读1、03010中Gank的全称是GangbangKill,是王者荣耀手游中常用的战术

河南新乡1座中型水库出现自然

河南广电·大象新闻记者卢家民通讯员李娟受台风天气影响,新乡全...

栏目排行