Nestjs系列 Nestjs进阶(一)

风希落 / 2024-03-08 / 原文

自定义装饰器

简单使用

当 Nest 内置的装饰器不能满足开发需求时,可以自定义装饰器,其自定义装饰器的规则和 react 的自定义 hooks 较为相似,自定义时,其封装必须使用 Nest 的内置装饰器或者其它自定义装饰器,react 中是必须使用 react hooks,这一点规则类似。

使用命令快速创建一个 decotator 模板

nest g decorator role --flat

image

这就是一个最基础的自定义装饰器,然后创建一个 guard 模板,使用 guard。

image

自定义装饰器调用其它装饰器

当装饰器相使用过多且相似时,可以在自定义装饰器里通过 applyDecorators 组合多个其它装饰器(包括其它的自定义装饰器)

image

applyDecorators 可以将多个装饰器合并条用

自定义参数装饰器

createParamDecorator 顾名思义,创建参数装饰器。可以接收装饰器传入的参数,还内置了 ctx 上下文,用于获取 request、response 等参数。

image

Module 和 Provider 循环依赖问题

什么是循环依赖,比如 A 模块引用了 B 模块,而 B 模块也引用了 A 模块,在执行时,IOC 容器就不知道该先注入A 还是先注入 B。这就是 Nest 中的循环引用。
注:Springboot 大于 2.7 版本之后,已经默认禁止了循环引用。

首先做一个相互引用的示例:

image

此时启动之后报错

image

报错的主要错误信息就是:模块之间的存在循环依赖。需使用 forwardRef() 来避免。可以阅读文档 循环依赖

Module 之间的互相导入

对于 Module 之间导入时的循环引用可以使用如下方式

image

Service 之间的互相注入

对于 Service 层的互相注入,在 @Inject 时,则同样需要添加 forwardRef(),不然也会报错

image

总结

forwardRef 就是解决 Module 之间的互相导入,Service 之间的互相注入用的。其本质就是通过函数延迟解析,直到所有相关的模块都已被扫描并且注册到容器中。这样当函数被调用时,相关的模块已经可用,从而解决了循环依赖问题。

动态创建模块

provider 是可以通过 useFactory 动态生成数据的,详情可阅读 Nestjs基础(二)。Module 也是可以的。文档链接 动态模块

需要给 module 添加 register 静态方法,然后可以通过外部传入参数,在不同模块导入的时候,可以定义不同的数据

image

取值时,就还是使用 @Inject 注入

image

约定名称

动态模块的 register 方法并不是非要用此方法名,但 nest 约定了 3 种方法名,来分别用来做不同的事情

  • register
    • 用一次模块传一次配置,比如这次调用是 AModule.register({age:20}),下一次就是 BModule.register({aaa:2})
  • forRoot
    • 配置一次模块用多次,比如 AModule.forRoot({age:20}) 一次,之后就一直用这个 Module 配置,一般在 AppModule 里 import
    • forRootAsync 就是在配置时,有异步操作,比如需要异步拿到服务配置,才能进行静态配置的生成
  • forFeature
    • 使用了 forRoot 固定整体模块,用于局部的时候,可能需要再传一些配置,比如用 forRoot 指定了数据库链接信息,再用 forFeature 指定某个模块访问哪个数据库和表。

Nest 与 Express Fastify 的关系和切换

Express 是一个轻量级处理请求、响应的库,其基本使用如下:

import bodyParser from 'body-parser';
import express from 'express';
import http from 'http';
import router from './router';

const app = express();
app.use(bodyParser.json());

router(app);

const server = http.createServer(app);

server.listen(8848, () => {
  console.log('server running on http://localhost:8848');
});


// router.js
export default (app) => {
  app.post('/list', async (req, res, next) => {
    res.send({
	  code:200,
	  data:[]
	});
  });
};

但 Express 只是一个处理请求的库,并没有提供组织代码的架构能力,其处理能力也是由各种中间件支撑的,项目庞大之后,没有严格的代码架构规范是很难维护的。

目前 Node 服务有三种层次的架构

  • 直接使用 http、https 的模块
  • 使用 express、koa 这种库,koa 也可以算作企业级框架
  • Nest 这种企业级框架
    • Nest 的架构就类似于 java 中的 Springboot

Nest 并没有和 express 进行强绑定,只是做了一层抽象(通过自己封装的 HttpServer 的 interface )
image