logologo
文档仓库
文档仓库
logologo
开始

概述

第一步
控制器
提供者
模块
中间件
异常过滤器
管道
守卫
拦截器
自定义装饰器

基础

自定义提供程序
异步提供者
动态模块
注入作用域
循环依赖
模块引用
懒加载模块
执行上下文
生命周期事件
发现服务
平台无关
单元测试

技术

配置
SQL
Mongo
验证
缓存
序列化
版本控制
任务调度
队列
日志
Cookies
事件
压缩
文件上传
文件流
HTTP 模块
Session
MVC
性能(Fastify)
SSE

安全

认证
授权
加密与哈希
Helmet
CORS
CSRF
速率限制

GraphQL

快速开始
解析器
变更
订阅
标量
指令
接口
联合与枚举
字段中间件
类型映射
插件
复杂度
扩展
CLI 插件
生成SDL
共享模型
其他功能
联邦

WebSocket

网关
异常过滤器
管道
守卫
拦截器
适配器

微服务

基础
Redis
MQTT
NATS
RabbitMQ
Kafka
gRPC
自定义传输
异常过滤器
管道
守卫
拦截器
部署
独立应用程序

CLI

概述
工作区
库
用法
脚本

OpenAPI

介绍
装饰器
类型映射
操作
其他特性
安全
类型与参数
CLI 插件

实用示例

REPL
CRUD生成器
SWC
Passport(认证)
热重载
MikroORM
TypeORM
Mongoose
Sequelize
路由模块
Swagger
健康检查
CQRS
Compodoc
Prisma
Sentry
静态资源
Commander
异步本地存储
Necord
套件(原Automock)

常见问题

Serverless
HTTP 适配器
长连接
全局前缀
原始请求体
混合应用
HTTPS & 多服务器
请求生命周期
错误

开发工具

概述
CI/CD
迁移指南
API参考(官方)

生态与案例

谁在用
精彩资源

支持

支持

社区

贡献者

最后更新于: 2025/11/18 02:11:37

上一页提供者
下一页中间件

#模块

模块是一个用 @Module() 装饰器注解的类。该装饰器提供了元数据,Nest 使用它来有效地组织和管理应用程序结构。

每个 Nest 应用程序至少有一个模块,即 根模块 ,它是 Nest 构建应用程序图的起点。该图是一种内部结构,Nest 利用它来解决模块和提供程序(提供者)之间的关系和依赖性问题。虽然小型应用程序可能只有一个根模块,但一般情况并非如此。强烈推荐使用模块作为组织组件的有效方式。对于大多数应用程序,您可能会拥有多个模块,每个模块都封装了一组密切相关的功能 。

@Module() 装饰器接收一个带有描述模块属性的对象:

属性
providers将由 Nest 注入器实例化,且至少可在本模块内共享的提供者
controllers本模块中定义的需要实例化的控制器集合
imports导入模块的列表,这些模块导出了本模块所需的提供者
exports本模块提供的 providers 子集,这些提供者应可供导入本模块的其他模块使用。可以使用提供者本身或其令牌(provide 值)

默认情况下,模块封装了提供者,这意味着您只能注入属于当前模块或从其他导入模块显式导出的提供者。模块导出的提供者本质上充当了该模块的公共接口或 API。

#功能模块

在我们的示例中,CatsController 和 CatsService 密切相关并服务于同一应用领域。将它们分组到功能模块中是合理的做法。功能模块用于组织与特定功能相关的代码,有助于保持清晰的边界和更好的组织结构。随着应用程序或团队规模的增长,这一点尤为重要,同时也符合 SOLID 原则。

接下来,我们将创建 CatsModule 来演示如何将控制器和服务进行分组。

cats/cats.module.ts
import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';

@Module({
 controllers: [CatsController],
 providers: [CatsService],
})
export class CatsModule {}
提示

要使用 CLI 创建模块,只需执行 $ nest g module cats 命令。

如上所述,我们在 cats.module.ts 文件中定义了 CatsModule,并将与此模块相关的所有内容移至 cats 目录。最后需要做的是将此模块导入根模块(即 AppModule,定义在 app.module.ts 文件中)。

app.module.ts
import { Module } from '@nestjs/common';
import { CatsModule } from './cats/cats.module';

@Module({
 imports: [CatsModule],
})
export class AppModule {}

以下是当前目录结构:

src
cats
dto
create-cat.dto.ts
interfaces
cat.interface.ts
cats.controller.ts
cats.module.ts
cats.service.ts
app.module.ts
main.ts

#共享模块

在 Nest 中,模块默认是单例的,因此您可以轻松地在多个模块之间共享同一个提供者实例。

每个模块自动成为共享模块 。一旦创建,它就可以被任何模块重复使用。假设我们想在多个其他模块之间共享 CatsService 的实例。为此,我们首先需要通过将该提供者添加到模块的 exports 数组来导出 CatsService,如下所示:

cats.module.ts
import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';

@Module({
 controllers: [CatsController],
 providers: [CatsService],
 exports: [CatsService]
})
export class CatsModule {}

现在任何导入 CatsModule 的模块都可以访问 CatsService,并且将与所有其他导入该模块的模块共享同一个实例。

如果我们在每个需要 CatsService 的模块中直接注册它,确实可以工作,但这会导致每个模块都获得自己独立的 CatsService 实例。这会增加内存使用量,因为创建了同一服务的多个实例,如果该服务维护任何内部状态,还可能导致意外行为,例如状态不一致。

通过将 CatsService 封装在模块中(例如 CatsModule)并将其导出,我们确保导入 CatsModule 的所有模块都重用同一个 CatsService 实例。这不仅减少了内存消耗,还带来了更可预测的行为,因为所有模块共享同一实例,使得管理共享状态或资源更加容易。这是 NestJS 等框架中模块化和依赖注入的关键优势之一——允许服务在整个应用程序中高效共享。

#模块再导出

如上所示,模块可以导出其内部提供者。此外,它们还能重新导出所导入的模块。在以下示例中,CommonModule 既被导入到 又 从 CoreModule 中导出,使得导入该模块的其他模块也能使用它。

@Module({
  imports: [CommonModule],
  exports: [CommonModule],
})
export class CoreModule {}

#依赖注入

模块类本身也可以 注入 提供者(例如用于配置目的):

cats.module.ts
import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';

@Module({
 controllers: [CatsController],
 providers: [CatsService],
})
export class CatsModule {
 constructor(private catsService: CatsService) {}
}

但由于 循环依赖 的存在,模块类本身不能作为提供者被注入。

#全局模块

如果需要在各处导入相同的模块集,可能会显得繁琐。与 Nest 不同,Angular 的 providers 注册在全局作用域中,一旦定义即可随处使用。而 Nest 则将提供者封装在模块作用域内,除非先导入封装模块,否则无法在其他地方使用模块的提供者。

当需要提供一组开箱即用的全局提供者(如辅助工具、数据库连接等)时,可使用 @Global() 装饰器将模块标记为全局模块。

import { Module, Global } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';

@Global()
@Module({
  controllers: [CatsController],
  providers: [CatsService],
  exports: [CatsService],
})
export class CatsModule {}

@Global() 装饰器使模块具有全局作用域。全局模块通常应由根模块或核心模块仅注册一次。在上例中,CatsService 提供者将无处不在,希望注入该服务的模块无需在其 imports 数组中导入 CatsModule。

提示

从设计实践角度不推荐将所有内容全局化。虽然全局模块能减少样板代码,但通常更好的做法是使用 imports 数组来可控且清晰地暴露模块 API 给其他模块。这种方式能提供更好的结构和可维护性,确保只共享模块的必要部分,同时避免应用无关部分之间产生不必要的耦合。

#动态模块

Nest 中的动态模块允许创建可在运行时配置的模块。当需要提供灵活、可定制的模块(其提供者能根据特定选项或配置创建时)特别有用。以下是关于动态模块运作原理的简要说明。

import { Module, DynamicModule } from '@nestjs/common';
import { createDatabaseProviders } from './database.providers';
import { Connection } from './connection.provider';

@Module({
  providers: [Connection],
  exports: [Connection],
})
export class DatabaseModule {
  static forRoot(entities = [], options?): DynamicModule {
    const providers = createDatabaseProviders(options, entities);
    return {
      module: DatabaseModule,
      providers: providers,
      exports: providers,
    };
  }
}
提示

forRoot() 方法可以同步或异步(例如通过 Promise)返回动态模块。

该模块默认定义了 Connection 提供者(在 @Module() 装饰器元数据中),此外根据传入 forRoot() 方法的 entities 和 options 对象,还会暴露一系列提供者,例如存储库。请注意动态模块返回的属性会扩展 (而非覆盖)@Module() 装饰器中定义的基础模块元数据。这样既保留了静态声明的 Connection 提供者又能导出动态生成的存储库提供者。

若需在全局范围注册动态模块,请将 global 属性设为 true。

{
  global: true,
  module: DatabaseModule,
  providers: providers,
  exports: providers,
}
警告

如前所述,将所有内容全局化并非良好的设计决策。

可按以下方式导入并配置 DatabaseModule:

import { Module } from '@nestjs/common';
import { DatabaseModule } from './database/database.module';
import { User } from './users/entities/user.entity';

@Module({
  imports: [DatabaseModule.forRoot([User])],
})
export class AppModule {}

若需重新导出动态模块,可在导出数组中省略 forRoot() 方法调用:

import { Module } from '@nestjs/common';
import { DatabaseModule } from './database/database.module';
import { User } from './users/entities/user.entity';

@Module({
  imports: [DatabaseModule.forRoot([User])],
  exports: [DatabaseModule],
})
export class AppModule {}

动态模块章节对此主题有更详细讲解,并包含一个实际示例 。

提示

通过本章节学习如何使用 ConfigurableModuleBuilder 构建高度可定制的动态模块。