为什么从egg.js到nest.js(一)

简介: 进入部门工作后,接触到的node.js服务端框架,是egg.js,后面基于扩展增加了很多插件,比如:@Controller @Service等注解,还有针对egg-framework 定制化部门使用的底层framework。

背景


进入部门工作后,接触到的node.js服务端框架,是egg.js,后面基于扩展增加了很多插件,比如:@Controller @Service等注解,还有针对egg-framework 定制化部门使用的底层framework。


但是,随着时间的迁移,egg已经不太能满足我们的开发效率和开发模式,主要有以下几点:

  • 对typescript支持度不够,这是由于egg.js本身就不是typescript开发
  • egg.js封装web架构,约定大于编码,如:强制将web应用分级为: controller、service、middleware、extend等,自由度相对比较弱,当你需要定制化开发内容,你需要深入了解egg.js的整个运行原理才能实现
  • 虽然部门内部定制化开发 @Controller @Service等注解,减少路由配置,但是这一块插件还存在一些隐藏规则,需要开发注意


当然egg.js运行的web应用还是比较稳定,而且相关插件生态也比较丰富,只是当egg.js迭代更新速度在2020年后就逐步放缓,更不上变化,我们就需要迎接一些新的框架来满足要求。

框架对比


我从近两年听到或者网上收集的,基于Node.js的框架主要有以下几个:

  • 基础框架,基本上还是以express、koa、Fastify.js等为主
  • egg.js,以MVC为架构的web框架
  • nest.js,以Ioc 控制反转作为核心概念的web框架,对typescript支持友好
  • nuxt.js,以Vue.js作为SSR服务端渲染核心的web框架,最新是Nuxt3(以Vue3为核心)
  • next.js,以React.js作为SSR服务端渲染核心的
  • Meteor.js,full-stack javascript平台,最大的特点是当数据发生改变的时候,所有依赖该数据的地方自动发生相应的改变。
  • Fastify.js,号称最快的node.js web框架,特点是内置了基于 JSON schema 的 validation 和 serialization,比JSON.stringify还快的json序列化算法,虽然是借助借助第三方库 ajv。
  • strapi.js,快速生成API接口的web框架,同时实现各种后端所需要的鉴权、权限、文件上传等轮子


对比一下,我们主要用来开发后端api接口,不需要SSR,不需要过于重或过于轻量的框架,因此最后挑选了nest.js。

nest.js


Nest (NestJS) 是一个用于构建高效、可扩展的Node.js服务器端应用程序的框架。它使用渐进式 JavaScript,构建并完全支持TypeScript(但仍然允许开发人员使用纯 JavaScript 进行编码)并结合了 OOP(面向对象编程)、FP(函数式编程)和 FRP(函数式响应式编程)的元素。

术语介绍:

  • 什么是渐进式?简单说,就一开始你不需要了解它的全部功能,能快速上手,有些功能特性不用也可以正常使用。
  • OOP 面向对象编程,万物皆可用对象来描述,如: class Dog{ say(return 'one one!')}
  • FP 函数式编程,以函数作为入口,而不是去声明一个对象类,如: say('one one!')
  • RP 响应式编程,一种面向数据流和变化传播的编程范式,如:a = 5; b=6; c=a+b; ab变化的时候,c会随之变化
  • FRP 函数式响应式编程,依赖数据流的函数式编程,如:str='one one~'; say(str), 当str变化,会自动触发say

基础概念


Nest.js的核心是基于IoC控制反转 + DI 依赖注入 去实现类的声明和实例化的。如果你了解过Spring Boot其实很容易上手nest.js。

Module


Module 其实是nest.js用来将一个web应用拆分成各个子模块的分类规定,web应用根模块一般叫app.module.ts,官方设计图如下:

ff59188ace5204cebf4bc097d33f801.png

Module应该由以下几个部分组成:

  • providers: 允许交给模块实例化的类,包括不限于Service等
  • controllers:必须实例的controller类
  • imports: 模块依赖其他模块
  • exports:模块对外提供的方法类

Controller


Controller就一个作用,分割路由,调用处理方法,返回http请求结果。

d642069f2cb5e3f5ce2e055ae5c8f70.png

支持写法:

  • @Controller('test')
  • @Get()@Post()@Put()@Del()代表各种请求方法(http Method)
  • 还支持一些特殊写法: @Session()  @Body(key?: string)@Param(key?: string)

Provider


Provider其实就是不仅仅是Service层,还包括:Sql的Dao层、工具方法等提供。它和其他层关系如下图:

d23f6e908b205c99d2d3d82abe60c14.png

写法:

  • @Injectable() 声明该类是一个Provider,允许其他类实现依赖注入
  • @Optional() 允许构造不传
  • @Inject() 自动依赖注入

Middleware


Middleware中间件,其实和egg.js的中间件概念一样,就是当http请求来了之后,被中间件处理一遍之后才会到对应的Controller层。

e22220b2ab3834be249a4755926459e.png

写法:

  • implements NestMiddleware,必须实现NestMiddleware接口,以及内部方法use(req: Request, res: Response, next: NextFunction),同时内部方法必须调用next
  • Module层注册中间件,这里需要可以设置
import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { LoggerMiddleware } from './common/middleware/logger.middleware';
import { CatsModule } from './cats/cats.module';
@Module({
  imports: [CatsModule],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoggerMiddleware)
      .forRoutes('cats');
  }
}
  • 了解 MiddlewareConsumer,中间件消费者工具类,主要把中间件加上一些配置项功能,如:forRoutes支持路由匹配,exclude不包含路由
  • 函数式声明中间件,因为Middleware是基于expres,所以写法与express基本上一致
import { Request, Response, NextFunction } from 'express';
export function logger(req: Request, res: Response, next: NextFunction) {
  console.log(`Request...`);
  next();
};


ExceptionFilter


Filter过滤器,这个应该是所有web框架都具备的功能,拦截用户请求和web返回数据。在Nest.js中,只实现ExeptionFilter,你也可以基于这个去自定义自己的异常过滤器,具体如下图:

c1f715539db0c49c81afd7f218980ef.png

写法:

  • @Catch(HttpException) class HttpExceptionFilter implements ExceptionFilter 实现自定义异常过滤器
  • @UseFilters(new HttpExceptionFilter()) 能给具体接口包裹上一层自定义的异常过滤器

Pipe


Pipe 管道流,是指的Http请求里的内容数据流,它支持数据验证、数据转换等功能,有点类似Filter的功能。


写法:

  • @Param('id', ParseIntPipe) id: number,将参数id转换为number类型
  • class ValidationPipe implements PipeTransform自定义 Pipe,同时必须实现方法transform(value: any, metadata: ArgumentMetadata)
  • @UsePipes(new Pipe()),支持在controller配置自定义的Pipe

Guard


Guard 守卫,也是处Http请求中的一层特殊中间件,但是与中间件不同的时候,中间件不知道next()是去哪个执行代码,而Guard则可以获取ExecutionContext实例,可以获知整个请求的生命周期和内置内容,通常用来接口登录和权限控制。

cdb1bc3c9acf031bb4779b2515b4e96.png

写法:

  • class AuthGuard implements CanActivate
  • 必须实现方法canActivate(context: ExecutionContext): boolean | Promise | Observable
  • 注册使用:@UseGuards Controller层使用, app.useGlobalGuards(new RolesGuard()); 全局注册

Interceptor


Interceptor是面向切面编程理念影响的概念,它允许你在方法执行前后扩展原有函数功能,如:改变返回结果,扩展基本功能等,常用的场景:添加常规日志。

b48efc7648139c6beea35d6dcc11b30.png

写法:

  • class LoggingInterceptor implements NestInterceptor,自定义实现
  • intercept(context: ExecutionContext, next: CallHandler): Observable方法实现,同时需要返回对应结果next()
  • 注册使用:@UseInterceptors(LoggingInterceptor)可以在类或方法前进行注册, app.useGlobalInterceptors(new LoggingInterceptor());全局注册

其他


  • 自定义参数装饰器createParamDecorator,可以从request对象中抽取固定的参数。
  • applyDecorators 可以将多个装饰器 方法合在一起验证,然后形成一个新的注装饰器


PS: 装饰器是什么?

  • 装饰器在JavaScript中暂时是没有,只有TypeScript才可以实现一种语法糖
  • 装饰器使用 @expression 的形式,其中 expression 必须能够演算为在运行时调用的函数,其中包括装饰声明信息。
  • 自定义装饰器代码如下:
// 这是一个装饰器工厂——有助于将用户参数传给装饰器声明
function f() {
  console.log("f(): evaluated");
  return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log("f(): called");
  }
}
function g() {
  console.log("g(): evaluated");
  return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
    console.log("g(): called");
  }
}
class C {
  @f()
  @g()
  method() {}
}
// f(): evaluated
// g(): evaluated
// g(): called
// f(): called
目录
相关文章
|
5月前
uni-app 65egg.js聊天类chat.js封装(二)
uni-app 65egg.js聊天类chat.js封装(二)
48 1
|
3月前
|
存储 开发框架 JavaScript
Node中的AsyncLocalStorage 使用问题之egg.js 和 midwayjs 与 Koa.js 有什么关系
Node中的AsyncLocalStorage 使用问题之egg.js 和 midwayjs 与 Koa.js 有什么关系
|
3月前
|
开发框架 前端开发 关系型数据库
使用egg.js开发后端API接口系统 什么是Egg.js
使用egg.js开发后端API接口系统 什么是Egg.js
|
3月前
|
开发框架 监控 JavaScript
企业级node.js开发框架 【egg.js】 实用教程
企业级node.js开发框架 【egg.js】 实用教程
40 0
|
4月前
|
JavaScript Shell 开发者
怎样使用Nest.js快速构建高效Node.js应用?
这篇博客介绍了Nest.js,一个基于TypeScript的Node.js框架,适用于构建可维护和可扩展的服务器端应用。文章引导读者快速入门,包括安装Node.js和Nest.js CLI,创建新项目,安装依赖以及启动开发服务器。通过访问`http://localhost:3000`,可以看到"Hello World!",证明应用已成功运行。Nest.js因其模块化架构和强大的功能,成为现代Web开发的热门选择。
|
SQL JavaScript 关系型数据库
号称下一代Node.js,Typescript以及go的orm的prisma 浅谈如何在nest.js中使用
号称下一代Node.js,Typescript以及go的orm的prisma 浅谈如何在nest.js中使用
号称下一代Node.js,Typescript以及go的orm的prisma 浅谈如何在nest.js中使用
|
5月前
|
JSON JavaScript 前端开发
【前后端实战项目】Vue.js 和 Egg.js 开发企业级健康管理项目
【前后端实战项目】Vue.js 和 Egg.js 开发企业级健康管理项目
|
12月前
|
NoSQL JavaScript 中间件
Node.js Koa2 MongoDB Redis egg.js
Node.js Koa2 MongoDB Redis egg.js
Node.js Koa2 MongoDB Redis egg.js
|
JavaScript
为什么从egg.js到nest.js(二)
进入部门工作后,接触到的node.js服务端框架,是egg.js,后面基于扩展增加了很多插件,比如:@Controller @Service等注解,还有针对egg-framework 定制化部门使用的底层framework。
96 0
为什么从egg.js到nest.js(二)
|
SQL JavaScript 关系型数据库
保姆级教程——号称下一代Node.js,Typescript的orm的prisma 如何在nest.js中使用
保姆级教程——号称下一代Node.js,Typescript的orm的prisma 如何在nest.js中使用