为什么选择 Nestjs 作为服务端框架,而不是 Express?

NestJS 采用了 AOP 的概念,尤其是通过其提供的拦截器(Interceptors)、守卫(Guards)、管道(Pipes)和自定义装饰器来实现。这些功能在 NestJS 中用于处理各种横切关注点,实现业务逻辑与非业务逻辑的解耦。

AOP

AOP 的中文全称为 Aspect Oriented Programming,翻译成人话就是 面向切面编程,那么什么是切面呢?

你可以理解为一个汉堡,它的本质就是一个面包,在这里我们把它理解为我们的应用程序,我们要在扩展这个应用程序的时候,需要在里面添加更多的代码,而这个过程就是向这个面包加馅的过程。

汉堡模型中的 AOP,首先我们的汉堡包是应用程序的基础,而添加的馅料是横切关注点。

将馅料加入汉堡的过程类似于 AOP 的“织入”过程。在编程中,织入是指将横切关注点的代码(馅料)插入到应用程序的核心逻辑(面包)中的特定点。这种织入可以在编译时、加载时或运行时完成,具体取决于使用的 AOP 框架和技术。

切点定义了馅料应当被加入的具体位置(即在哪些方法或函数的哪些具体点)。通知则定义了加馅的具体行为,即当执行到切点时应当执行什么操作。通知的类型包括:前置通知(在主逻辑之前加馅)、后置通知(在主逻辑之后加馅)、环绕通知(在主逻辑前后都加馅)、抛出异常后的通知(在主逻辑抛出异常时加馅)等。

通过加馅,我们可以增加汉堡包的味道,同样地使用 AOP 可以增强应用程序的功能性和灵活性。它能够帮助开发者将关注点分离,提高代码的可维护性和可重用性,同时减少代码冗余。

NestJs 中的 AOP

NestJS 采用了 AOP 的概念,尤其是通过其提供的拦截器(Interceptors)、守卫(Guards)、管道(Pipes)和自定义装饰器来实现。这些功能在 NestJS 中用于处理各种横切关注点,实现业务逻辑与非业务逻辑的解耦。

我们先从一个大的概念来开始讲起,我们在前端发起一个 HTTP 网络请求,它首先会经过 Controller(控制器)、Services(服务)、Repository(数据接入) 的逻辑,它的主要流程如下图所示:

20240421160628

当获取到数据库中的数据之后,我们又通过了 Services 返回数据到 Controller 并最终返回到前端。在这里如果你想在这个调用链路里加入一些通用逻辑,我们可以在这个执行流程中加入不同的逻辑,这个就是 AOP 给我们带来的好处。

如下图所示,在 Nest 中,我们在前端发送一个网络请求到 NestJs,它可以通过这些组件:

20240421160915

每个阶段都有不同的逻辑,例如 Interceptors(拦截器),它分为前置拦截器和后置拦截器,前置拦截器又有这么三个逻辑,它们分别是全局拦截器、控制器拦截器、路由拦截器三个。