Skip to content

什么是 NestJS?它有什么优点和缺点?

查看详情
  • NestJS 是一个用于构建高效、可扩展的服务器端应用程序的渐进式 Node.js 框架。它利用现代 JavaScript(和 TypeScript)并结合了 OOP(面向对象编程)、FP(函数式编程)和 FRP(函数响应式编程)的元素,提供了丰富的功能和开发工具。
  • 优点
    • NestJS 提供了一套一致的代码结构和最佳实践,使得项目代码更加组织化和可维护。无论是小型项目还是大型企业级应用,NestJS 都能提供清晰的架构指导。
    • 强类型支持
    • 可扩展性:可根据需要添加或移除模块,而不会影响其他模块的功能。
    • 依赖注入:内置的依赖注入容器使得组件之间的依赖关系管理变得简单,有助于解耦和提高代码的可测试性。
    • NestJS 拥有庞大的社区和丰富的插件生态系统,支持多种数据库(如 TypeORM、Mongoose)、消息队列(如 RabbitMQ、Kafka)、验证和授权、GraphQL 等,几乎可以满足所有的后端开发需求。
  • 缺点
    • 学习曲线陡峭
    • 性能相对于轻量级的框架略低

什么是依赖注入(DI)?在 NestJS 中如何使用 DI?

查看详情
  • 依赖注入 (Dependency Injection) 是一种设计模式,主要用于降低代码之间的耦合度。它允许通过外部机制控制对象的依赖项,而不是在对象内部实例化。
  • 在 NestJS 中:
    • 通过 @Injectable() 装饰器将类标记为提供者 (Provider)。
    • 在类(比如 Controller 或 Service)的构造函数中声明依赖。NestJS 的控制反转(IoC)容器会在实例化类时,自动解析并注入这些依赖。

如何在 NestJS 中创建控制器(controller)和服务(service)

查看详情
  • 控制器 (Controller):负责接收客户端传入的请求并将响应返回给客户端。
    • 创建方法:使用 @Controller('路由前缀') 装饰器。例如:
      typescript
      @Controller('users')
      export class UsersController {}
  • 服务 (Service):负责处理具体的业务逻辑,通常作为依赖注入的 Provider 存在。
    • 创建方法:使用 @Injectable() 装饰器。例如:
      typescript
      @Injectable()
      export class UsersService {}
  • 将 Service 注入 Controller 中,只需在 Controller 的构造函数参数中声明引用即可:constructor(private readonly usersService: UsersService) {}

如何在 NestJS 中实现中间件(middleware)

查看详情
  • 中间件 是在路由处理程序之前调用的函数,可以用来执行任何代码、修改请求和响应对象、结束请求响应周期或调用栈中的下一个中间件(next())。
  • 实现方式:
    1. 创建一个类并实现 NestMiddleware 接口。
    2. 实现 @Injectable() 装饰的类里面的 use(req, res, next) 方法。
    3. 在 Module 中实现 NestModule 接口,并在 configure 方法中使用 consumer.apply().forRoutes() 将局部中间件绑定到特定的路由。也可在 main.ts 中通过 app.use() 挂载全局中间件。

什么是管道(pipe)?如何在 NestJS 中实现管道

查看详情
  • 管道 (Pipe):主要有两个典型的应用场景:
    • 转换:将输入数据转换为需要的格式(如将字符串转为整数)。
    • 验证:评估输入数据是否有效,如果有效原样传递,否则抛出异常。
  • 实现方式:使用 @Injectable() 装饰器创建一个类并实现 PipeTransform 接口,提供 transform(value, metadata) 方法。
  • 应用场景:管道能够在方法级别(@UsePipes())、参数级别(如 @Body(new ValidationPipe()))或全局级别(app.useGlobalPipes())使用。

如何在 NestJS 中使用拦截器(interceptor)

查看详情
  • 拦截器 (Interceptor):受 AOP(面向切面编程)启发,主要用于:
    • 在函数执行之前/之后绑定额外的逻辑
    • 转换从函数中返回的结果
    • 转换函数抛出的异常
    • 扩展基本功能以及在特定条件下覆盖原本逻辑(例如缓存)
  • 实现方式:实现 NestInterceptor 接口中的 intercept(context: ExecutionContext, next: CallHandler) 方法,通过 RxJS 的 Observable 操作流(响应返回流)。
  • 使用:通过 @UseInterceptors() 挂载。

如何在 NestJS 中进行数据验证(data validation)

查看详情
  • NestJS 通常结合 class-validatorclass-transformer 与内置的 ValidationPipe 来进行数据验证。
  • 步骤:
    1. 安装包:npm install class-validator class-transformer
    2. 启用全局验证管道:在 main.ts 中调用 app.useGlobalPipes(new ValidationPipe())
    3. 创建 DTO(数据传输对象),并使用 class-validator 提供的装饰器(如 @IsString(), @IsInt(), @IsNotEmpty())来约束属性。
    4. 在控制器的方法参数里使用该 DTO 类型来自动应用验证。

如何在 NestJS 中实现身份验证(authentication)和授权(authorization)

查看详情
  • 身份验证 (Authentication):验证用户是谁。通常使用 @nestjs/passportpassport 策略(如 JWT,Local 等)。
  • 授权 (Authorization):验证用户能做什么。通常通过 守卫 (Guard) 来实现。
    • 创建 Guard:使用 @Injectable() 并实现 CanActivate 接口的 canActivate 方法返回布尔值(或解析为布尔值的 Promise/Observable)以确定是否有权限访问。
    • 结合自定义装饰器(如 @Roles('admin'))与 Reflector 判断当前用户的权限标签。

如何在 NestJS 中处理异常(exception)和错误(error)

查看详情
  • 内置通过全局异常过滤器 (Exception Filter) 提供了一个开箱即用的基础异常处理层,自动处理所有未捕获异常。
  • 主动抛出异常:抛出内置的 HttpException 或派生类(如 BadRequestException, NotFoundException)。
  • 自定义异常过滤器
    1. 创建类实现 ExceptionFilter 接口。
    2. 使用 @Catch( HttpException ) 装饰器指定捕获的异常类型。
    3. 实现 catch(exception, host) 方法,从 ArgumentsHost 中提取 Response 对象来定制规范化的错误输出格式。

如何在 NestJS 中进行测试(testing)?

查看详情
  • NestJS 内置集成了 Jest 作为默认的测试框架,并提供专门的 @nestjs/testing 包用于创建测试环境床(Testing Module)。
  • 单元测试:不依赖外部系统,通过 Test.createTestingModule 动态编译模块注入 Mock 依赖,测试独立的方法逻辑。
  • 端到端(e2e)测试:模拟完整请求响应生命周期,结合 supertest 触发真实 Controller 的请求进行验证(通常放在 test/ 目录下)。

什么是 NestJS 中的模块(module)?如何在 NestJS 中创建和使用模块?

查看详情
  • 模块 (Module):是用 @Module() 装饰器注释的类,提供了组织应用程序结构的元数据,它是依赖注入图的基础构建块。一个应用至少要有一个根模块(AppModule)。
  • 配置组成:
    • controllers:包含该模块必须要实例化的控制器。
    • providers:由 Nest 注入器实例化的服务、提供者等。
    • imports:该模块需要的其他模块(包含导出 Providers 的模块)。
    • exports:将本模块里的 Providers 暴露给引入该模块的其他模块。

如何在 NestJS 中使用 Swagger 自动生成 API 文档?

查看详情
  • NestJS 提供了 @nestjs/swagger 包自动扫描生成 OpenAPI 规范文档。
  • 步骤:
    1. 安装 @nestjs/swaggerswagger-ui-express
    2. main.ts 使用 DocumentBuilder 构建基础文档配置(标题、描述、版本等)。
    3. 通过 SwaggerModule.createDocument 生成文档对象。
    4. 使用 SwaggerModule.setup('/api', app, document) 挂载特定路由访问 Swagger UI。
    5. 可以在 Controller 中配合 @ApiTags(), @ApiOperation(), @ApiResponse()、在 DTO 中配合 @ApiProperty() 完善字段注释。

如何在 NestJS 中实现缓存(cache)功能?

查看详情
  • NestJS 提供了 @nestjs/cache-manager 用于统一管理缓存。
  • 步骤:
    1. 安装 @nestjs/cache-managercache-manager
    2. 在 AppModule 中导入 CacheModule.register()
    3. 在 Controller 中可以通过挂载全局/局部的拦截器 @UseInterceptors(CacheInterceptor) 自动缓存所有的 GET 请求。
    4. 也可以在 Service 中通过 @Inject(CACHE_MANAGER) 直接注入 Cache 实例,使用 await this.cacheManager.get/set() 手动操作缓存,支持接入 Redis 等后端存储。

如何在 NestJS 中进行日志记录(logging)?

查看详情
  • NestJS 提供了内置的基于 Logger 类的日志记录系统。
  • 基础用法:private readonly logger = new Logger(MyService.name);,通过 this.logger.log(), error(), warn(), debug() 输出信息。
  • 全局日志:可以在微服务/程序初始化(NestFactory.create)时通过 logger: [...] 选项覆盖默认控制台输出。
  • 自定义:可以实现 LoggerService 接口,集成如 Winston、Pino 等专业日志库模块,以支持不同环境持久化、日志分割等复杂需求。

什么是 NestJS 中的全局拦截器(global interceptor)?如何在 NestJS 中使用全局拦截器?

查看详情
  • 全局拦截器是作用于整个应用程序中注册的所有控制器与路由的拦截器,通常用于统一返回体结构、记录全局访问日志、统一格式化响应数据等。
  • 使用方式:
    1. 方式一:在 main.ts 中直接使用 app.useGlobalInterceptors(new TransformInterceptor())。此法无法进行依赖解析注入。
    2. 方式二(推荐):在 AppModule 的 providers 数组中使用令牌注册,以允许依赖注入: { provide: APP_INTERCEPTOR, useClass: TransformInterceptor }

如何在 NestJS 中使用 Passport 实现多种身份验证策略?

查看详情
  • @nestjs/passport 包装了 Node 社区极其成熟的 Passport 库。
  • 实现:
    1. 每一个具体的验证实现可以看作一个 Strategy (策略),继承 PassportStrategy 并实现 validate 校验逻辑(例如 local, jwt, github 等)。
    2. Passport 根据策略将其结果塞入并生成 req.user 会话。
    3. 提供守卫支持:无需手写验证 Guard,直接继承 AuthGuard('jwt') 即可保护相应路由控制器。

如何在 NestJS 中使用 JWT 进行身份验证?

查看详情
  • 使用了 @nestjs/jwt@nestjs/passportpassport-jwt
  • 流程:
    1. 登录生成 JWT:客户端凭密码成功登录后,使用注入的 JwtService.sign(payload) 基于私钥生成 JWT 字符串,并返回到前端。
    2. 验证 JWT 策略:实现继承了 PassportStrategy(Strategy, 'jwt')JwtStrategy 类。配置中解析从请求头部的 Authorization Bearer Token 中提取出的 payload,执行 validate(payload) 判断有效性。
    3. 保护路由:通过给接口加上特定的 @UseGuards(AuthGuard('jwt')),对没有带有效 Token 的请求返回 401 失败。

如何在 NestJS 中使用 ACL 进行授权管理?

查看详情
  • 基于角色的访问控制(RBAC)/ 权限控制(ACL)在 NestJS 中结合**守卫(Guard)**进行处理。
  • 流程:
    1. 使用 @SetMetadata('roles', ['admin']) (推荐封装为自定义装饰器如 @Roles(...) )绑定当前路由需要的权限元信息。
    2. 编写 RolesGuard(实现 CanActivate 接口),通过 Reflector 反射读取路由绑定的元信息(roles),与验证后附加在 req.user 上的实际角色对比比对。
    3. 比对通过返回 true 授权放行,失败则返回 false 抛出错误(通常是 403 Forbidden)。

如何在 NestJS 中实现异步任务(asynchronous task)?

查看详情
  • NestJS 内置和集成常用于处理定时或耗时的异步微型任务的方案:
    • 定时任务 (Cron / Task Scheduling):通过 @nestjs/schedule 库提供 @Cron(), @Interval(), @Timeout() 装饰器,实现后台自动化任务调度。
    • 消息队列 (Bull/Redis):对于复杂的、消耗资源且可能需要重试机制的后台任务(如邮件、转码等),使用 @nestjs/bull。将消费者和生产者通过 Redis 解耦并处理庞大的作业队列。

如何在 NestJS 中使用 Docker 进行容器化部署?

查看详情
  • 为了部署 NestJS 应用程序,必须创建 Dockerfile 让其以独立、可重用的环境运行。
  • 大致编写逻辑:
    1. 基础镜像:基于 Node.js LTS 镜像,如 node:18-alpine
    2. 安装依赖:拷贝 package.json,执行 npm install
    3. 编译发布包:拷贝所有源码,执行 npm run build
    4. 多阶段构建:(生产镜像阶段) 仅复制必须模块,并运行 node dist/main.js
    5. 准备 .dockerignore 避免将本地的 node_modules 复制进去。

如何在 NestJS 中使用 Kubernetes 进行容器编排和部署?

查看详情
  • 在 Docker 容器化基础之上,通过声明式配置文件(YAML) 告诉 Kubernetes 如何部署运行。
  • 需要编写基本的:
    1. Deployment: 定义你的 Nest 应用副本数、镜像和更新策略。
    2. Service: 暴露 Pod 中 Nest 应用的端口以提供内部负载均衡服务。
    3. ConfigMap / Secret: 注入应用需要的安全认证信息与环境变量。
    4. Ingress: (如果暴露到公网)用于路由外部 HTTP 请求访问你的 Service。
    • 通过 kubectl apply -f xx.yaml 启动集群内的各个资源即可完成部署管理。

什么是 NestJS 中的异步模块(async module)?如何使用异步模块?

查看详情
  • 当模块的提供者 (如数据库连接、统一配置中心等) 初始化需要根据异步操作或者提取环境变量时,应该使用异步模块模式(Dynamic Modules 动态模块异步定义)。
  • 常用方法名如 .registerAsync().forRootAsync()
  • 实现:依赖于 useFactory 属性传递一个能够返回配置的工厂函数(可以使其为 async),并且可以使用 inject 属性请求依赖于已经注入的别的 Providers (比如 ConfigService) 读取配置文件后实例化。

NestJS 中如何进行环境变量配置?

查看详情
  • NestJS 推荐使用 @nestjs/config 包,底层包裹了 dotenv 用于解析 .env
  • 在 AppModule 中导入:
    typescript
    ConfigModule.forRoot({
      isGlobal: true,    // 作用于全局
      envFilePath: '.env', // 指定路径,或者按条件配置不同的环境文件
    })
  • 读取方式:随后可以在任意 Service 中注入内部集成的 ConfigService ,调用 this.configService.get<string>('DATABASE_USER') 安全读取。