大白话讲透 NestJS:所有核心概念 + 源码逻辑

4 阅读15分钟

很多人学 NestJS 总卡在:模块、依赖注入、装饰器、中间件 / 守卫 / 拦截器 / 管道…… 一堆概念混在一起,源码更是看不懂。本文用最通俗的大白话,把 NestJS 所有核心概念讲透,再带你扒一遍核心源码逻辑,看完你会发现:NestJS 其实就是一套 “标准化 + 自动管理” 的 Node.js 后端架构,一点都不复杂。


一、先搞懂:NestJS 到底是什么?(一句话大白话)

NestJS 就是给 Node.js 后端定规矩的框架

  • 它不像 Express 那样 “自由到混乱”,而是强制你按模块 → 控制器 → 服务的结构写代码。
  • 它内置依赖注入容器,自动帮你创建、管理、传递对象,不用你手动 new、不用你处理依赖关系。
  • 它用装饰器@Controller/@Get/@Module)把 “配置” 和 “代码” 分开,写起来像写注释一样简单。
  • 底层跑在 Express(默认)或 Fastify 上,你既享受框架规范,又能直接用 Express 生态。

一句话总结:NestJS = 模块化 + 依赖注入 + 装饰器驱动 + Express/Fastify 底层


二、NestJS 三大核心理念(大白话版)

NestJS 所有设计都围绕这 3 点,看懂这 3 点,你就看懂了 80% 的 NestJS。

2.1 模块化(Modularity):像搭乐高一样写代码

  • 大白话解释:把一个大应用拆成一个个独立的 “小盒子”(模块),每个盒子只做一件事(比如用户模块、文章模块、评论模块)。
  • 好处:代码不混乱、依赖清晰、可复用、可测试、大型项目好协作。
  • 对比 Express:Express 只有文件夹,没有强制边界;NestJS 有 @Module 装饰器,强制每个功能一个模块。

2.2 依赖注入(DI):框架帮你 “递东西”,不用你自己找

  • 大白话解释:你需要一个服务(比如 UserService),不用自己 new UserService(),直接在构造函数里写 constructor(private userService: UserService),框架自动把实例传给你。
  • 好处:解耦、可 Mock、可单测、不用管对象生命周期。
  • 核心原理:NestJS 有个IoC 容器(控制反转容器),它像一个 “对象仓库”,所有可注入的对象都存在这里,需要时直接取。

2.3 装饰器驱动(Decorator-Driven):用 “标签” 定义行为,不用写复杂配置

  • 大白话解释:用 @ 开头的装饰器(比如 @Controller/@Get/@Injectable)给类、方法、参数 “打标签”,告诉 NestJS 这个类 / 方法是干嘛的。
  • 好处:代码简洁、可读性强、元数据和业务代码分离。
  • 例子@Controller('users') 告诉 NestJS:这个类是控制器,处理 /users 开头的请求;@Get() 告诉 NestJS:这个方法处理 GET 请求。

三、NestJS 核心概念全解(大白话 + 代码 + 源码逻辑)

3.1 模块(Module):NestJS 的 “基本单元”(最重要)

3.1.1 大白话解释

模块就是一个功能的完整封装,包含:

  • 控制器(处理请求)
  • 服务(业务逻辑)
  • 导入其他模块(依赖)
  • 导出服务(给其他模块用)

每个 NestJS 应用至少有一个根模块(AppModule) ,所有功能都从根模块开始组织。

3.1.2 代码示例(最标准的模块)

typescript

运行

// src/app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UsersModule } from './users/users.module'; // 导入用户模块

@Module({
  imports: [UsersModule], // 导入其他模块(依赖)
  controllers: [AppController], // 本模块的控制器
  providers: [AppService], // 本模块的服务(可注入)
  exports: [AppService], // 导出服务,供其他模块使用
})
export class AppModule {}

3.1.3 源码逻辑(NestJS 如何处理模块)

NestJS 源码中,模块的核心逻辑在 @nestjs/coreinjectorscanner 模块里:

  1. 扫描模块Scanner 类扫描所有 @Module 装饰器,收集模块元数据(imports/controllers/providers/exports)。
  2. 构建模块图谱NestContainer(IoC 容器)构建模块依赖关系图,检测循环依赖。
  3. 实例化模块:按依赖顺序实例化模块,先实例化被依赖的模块,再实例化依赖它的模块。
  4. 注册到容器:把模块、控制器、服务都注册到 NestContainer 中,方便后续依赖注入。

3.1.4 模块的 4 个核心属性(必须懂)

  • imports:导入其他模块,代表 “我需要用别人的功能”。
  • controllers:注册本模块的控制器,NestJS 会自动把这些控制器挂载到路由系统。
  • providers:注册本模块的服务(可注入对象),这些服务只能在本模块内使用(除非导出)。
  • exports:导出服务,代表 “我的服务可以给其他模块用”。

3.2 控制器(Controller):请求的 “入口”

3.2.1 大白话解释

控制器就是处理 HTTP 请求的 “服务员”

  • 接收请求(GET/POST/PUT/DELETE)
  • 解析参数(query/params/body)
  • 调用服务(Service)处理业务逻辑
  • 返回响应给客户端

原则:控制器只做 “协调”,不写业务逻辑,业务逻辑全部放在服务里。

3.2.2 代码示例(最标准的控制器)

typescript

运行

// src/app.controller.ts
import { Controller, Get, Post, Body, Param, Query } from '@nestjs/common';
import { AppService } from './app.service';

@Controller('app') // 前缀:所有路由都以 /app 开头
export class AppController {
  // 依赖注入:自动获取 AppService 实例
  constructor(private readonly appService: AppService) {}

  @Get() // 处理 GET /app
  getHello(@Query('name') name: string): string {
    return this.appService.getHello(name);
  }

  @Post('user') // 处理 POST /app/user
  createUser(@Body() user: { name: string; age: number }) {
    return this.appService.createUser(user);
  }

  @Get('user/:id') // 处理 GET /app/user/123
  getUser(@Param('id') id: string) {
    return this.appService.getUser(id);
  }
}

3.2.3 源码逻辑(NestJS 如何注册控制器路由)

控制器路由注册逻辑在 @nestjs/core/router 模块里:

  1. 收集路由元数据RouterExplorer 扫描控制器的 @Controller/@Get/@Post 等装饰器,收集路由路径、请求方法、参数装饰器元数据。
  2. 绑定到底层 HTTP 框架:把收集到的路由绑定到 Express/Fastify 的路由系统,比如 app.get('/app', handler)
  3. 参数解析:请求进来时,RouterExecutionContext 解析 @Param/@Query/@Body 等参数,自动注入到方法参数中。

3.2.4 常用控制器装饰器(必须记)

  • @Controller(prefix):定义控制器前缀
  • @Get()/@Post()/@Put()/@Delete():定义请求方法和路由
  • @Param(key):获取 URL 参数(如 /user/:id
  • @Query(key):获取查询参数(如 ?name=xxx
  • @Body():获取请求体
  • @Headers():获取请求头
  • @Res():获取原生 Response 对象(Express/Fastify)

3.3 服务(Service):业务逻辑的 “大脑”

3.3.1 大白话解释

服务就是写业务逻辑的地方,所有复杂逻辑(数据库操作、第三方接口调用、计算逻辑)都放在服务里。

  • 服务用 @Injectable() 装饰器标记,代表 “可被依赖注入”。
  • 服务可以被控制器、其他服务、守卫、拦截器等注入使用。

3.3.2 代码示例(最标准的服务)

typescript

运行

// src/app.service.ts
import { Injectable } from '@nestjs/common';

@Injectable() // 标记为可注入
export class AppService {
  getHello(name: string): string {
    return `Hello ${name || 'World'}!`;
  }

  createUser(user: { name: string; age: number }) {
    // 这里写业务逻辑:数据库插入、校验、第三方调用等
    return { id: Date.now(), ...user };
  }

  getUser(id: string) {
    // 这里写业务逻辑:数据库查询
    return { id, name: '张三', age: 20 };
  }
}

3.3.3 源码逻辑(NestJS 如何实例化服务)

服务实例化逻辑在 @nestjs/core/injector 模块里:

  1. 标记可注入@Injectable() 装饰器给类添加元数据,告诉 IoC 容器:这个类可以被注入。
  2. 注册到容器:模块扫描时,NestContainer 把服务类注册到容器中。
  3. 依赖解析:当控制器 / 其他服务需要注入这个服务时,Injector 类解析服务的依赖(构造函数参数),先实例化依赖,再实例化当前服务。
  4. 单例模式:默认情况下,服务是单例的,整个应用只有一个实例,节省内存。

3.4 提供者(Provider):NestJS 的 “可注入对象”

3.4.1 大白话解释

提供者就是所有可以被依赖注入的对象,包括:

  • 服务(Service):最常见的提供者
  • 工厂(Factory):动态创建对象
  • 值(Value):直接提供一个值
  • 自定义类:任何用 @Injectable() 标记的类

核心:只要是 providers 数组里的东西,都是提供者,都可以被注入。

3.4.2 提供者的 4 种类型(必须懂)

1. 类提供者(最常用)

typescript

运行

@Module({
  providers: [AppService], // 类提供者
})
2. 值提供者

typescript

运行

@Module({
  providers: [
    {
      provide: 'APP_NAME', // 注入令牌
      useValue: 'My Nest App', // 提供的值
    },
  ],
})
// 使用:constructor(@Inject('APP_NAME') private appName: string)
3. 工厂提供者(动态创建)

typescript

运行

@Module({
  providers: [
    {
      provide: 'CONFIG',
      useFactory: (configService: ConfigService) => {
        return configService.getConfig(); // 动态创建
      },
      inject: [ConfigService], // 依赖
    },
  ],
})
4. 异步提供者(延迟加载)

typescript

运行

@Module({
  providers: [
    {
      provide: 'DATABASE_CONNECTION',
      useFactory: async () => {
        const connection = await createConnection(); // 异步创建
        return connection;
      },
    },
  ],
})

3.4.3 源码逻辑(提供者如何工作)

提供者的核心逻辑在 NestContainerInjector 中:

  • 每个提供者都有一个注入令牌(provide) ,可以是字符串、类、符号。
  • Injector 根据令牌从容器中查找对应的提供者,然后实例化 / 返回值。
  • 依赖解析是递归的:如果提供者 A 依赖提供者 B,NestJS 会先实例化 B,再实例化 A。

3.5 中间件(Middleware):请求的 “第一道关卡”

3.5.1 大白话解释

中间件就是在请求到达控制器之前 / 之后执行的函数,可以:

  • 记录日志
  • 解析请求
  • 校验权限
  • 修改请求 / 响应对象
  • 终止请求(比如权限不足)

对比 Express:NestJS 中间件和 Express 中间件完全兼容,你可以直接用 Express 中间件。

3.5.2 代码示例(自定义中间件)

typescript

运行

// src/middleware/logger.middleware.ts
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
    next(); // 调用下一个中间件/控制器
  }
}

// 注册中间件(在模块中)
@Module({})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoggerMiddleware) // 应用中间件
      .forRoutes('*'); // 对所有路由生效
  }
}

3.5.3 源码逻辑(中间件执行顺序)

中间件执行逻辑在 @nestjs/core/middleware 模块里:

  1. 注册中间件MiddlewareConsumer 把中间件绑定到指定路由。
  2. 执行顺序:请求进来时,先执行全局中间件,再执行模块中间件,然后执行守卫 / 拦截器 / 管道,最后执行控制器。
  3. 链式调用:中间件通过 next() 函数链式执行,任何一个中间件不调用 next(),请求就会终止。

3.6 守卫(Guard):权限的 “看门人”

3.6.1 大白话解释

守卫就是判断 “是否允许请求继续” 的函数,核心作用是权限控制

  • 守卫返回 true:允许请求继续
  • 守卫返回 false:拒绝请求,返回 403 Forbidden
  • 守卫可以作用于控制器、方法、全局

3.6.2 代码示例(JWT 守卫)

typescript

运行

// src/guard/jwt.guard.ts
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';

@Injectable()
export class JwtGuard implements CanActivate {
  constructor(private jwtService: JwtService) {}

  canActivate(context: ExecutionContext): boolean {
    const request = context.switchToHttp().getRequest();
    const token = request.headers.authorization?.split(' ')[1];
    if (!token) return false;

    try {
      const user = this.jwtService.verify(token);
      request.user = user; // 把用户信息挂到请求上
      return true;
    } catch (e) {
      return false;
    }
  }
}

// 使用守卫(控制器/方法上)
@Controller('users')
@UseGuards(JwtGuard) // 整个控制器需要登录
export class UsersController {
  @Get()
  getUsers() { /* ... */ }
}

3.6.3 源码逻辑(守卫如何执行)

守卫执行逻辑在 @nestjs/core/guards 模块里:

  1. 收集守卫ExecutionContext 收集当前请求的守卫(全局、控制器、方法)。
  2. 顺序执行:按 “全局 → 控制器 → 方法” 的顺序执行所有守卫。
  3. 短路机制:只要有一个守卫返回 false,立即终止请求,返回 403。
  4. 上下文ExecutionContext 提供请求、响应、类、方法等上下文信息,方便守卫获取数据。

3.7 拦截器(Interceptor):请求 / 响应的 “编辑器”

3.7.1 大白话解释

拦截器就是在请求到达控制器之前、响应返回客户端之后,修改请求 / 响应的函数

  • 可以修改请求参数
  • 可以修改响应数据
  • 可以统一格式化响应
  • 可以捕获异常
  • 可以添加缓存逻辑
  • 可以统计耗时

3.7.2 代码示例(统一响应格式拦截器)

typescript

运行

// src/interceptor/transform.interceptor.ts
import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

@Injectable()
export class TransformInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    return next.handle().pipe(
      map((data) => {
        // 统一响应格式:{ code: 200, data, message: 'success' }
        return {
          code: 200,
          data,
          message: 'success',
        };
      }),
    );
  }
}

// 注册全局拦截器
@Module({
  providers: [
    {
      provide: APP_INTERCEPTOR,
      useClass: TransformInterceptor,
    },
  ],
})
export class AppModule {}

3.7.3 源码逻辑(拦截器如何工作)

拦截器执行逻辑在 @nestjs/core/interceptors 模块里:

  1. Observable 流:拦截器基于 RxJS 的 Observable 流,支持异步、链式操作。
  2. 执行顺序:请求阶段:全局拦截器 → 控制器拦截器 → 方法拦截器;响应阶段:方法拦截器 → 控制器拦截器 → 全局拦截器。
  3. handle()next.handle() 触发控制器方法执行,返回 Observable 流,拦截器可以通过 pipe() 操作这个流。

3.8 管道(Pipe):参数的 “校验器 / 转换器”

3.8.1 大白话解释

管道就是在参数进入控制器方法之前,校验 / 转换参数的函数

  • 校验:判断参数是否合法(比如是否为空、是否符合格式)
  • 转换:把参数转换成需要的类型(比如字符串转数字、字符串转日期)
  • NestJS 内置很多管道(ValidationPipe/ParseIntPipe/ParseUUIDPipe

3.8.2 代码示例(参数校验管道)

typescript

运行

// src/pipe/validation.pipe.ts
import { ArgumentMetadata, Injectable, PipeTransform, BadRequestException } from '@nestjs/common';
import { validate } from 'class-validator';
import { plainToInstance } from 'class-transformer';

@Injectable()
export class ValidationPipe implements PipeTransform {
  async transform(value: any, metadata: ArgumentMetadata) {
    const { metatype } = metadata;
    if (!metatype || !this.toValidate(metatype)) {
      return value;
    }

    const object = plainToInstance(metatype, value);
    const errors = await validate(object);
    if (errors.length > 0) {
      throw new BadRequestException('参数校验失败');
    }
    return value;
  }

  private toValidate(metatype: Function): boolean {
    const types: Function[] = [String, Boolean, Number, Array, Object];
    return !types.includes(metatype);
  }
}

// 使用管道(方法参数上)
@Post('user')
createUser(@Body(new ValidationPipe()) user: CreateUserDto) {
  return this.appService.createUser(user);
}

3.8.3 源码逻辑(管道如何执行)

管道执行逻辑在 @nestjs/core/pipes 模块里:

  1. 参数解析:请求进来时,RouterExecutionContext 解析参数装饰器,收集参数元数据。
  2. 执行管道:按 “全局管道 → 控制器管道 → 方法管道 → 参数管道” 的顺序执行。
  3. 转换 / 校验:管道对参数进行转换 / 校验,不合法则抛出异常,合法则返回转换后的参数。

3.9 过滤器(Filter):异常的 “捕获器”

3.9.1 大白话解释

过滤器就是捕获控制器 / 服务抛出的异常,统一返回错误响应的函数

  • 可以捕获所有异常@Catch()
  • 可以捕获特定异常@Catch(HttpException)
  • 可以自定义错误响应格式

3.9.2 代码示例(全局异常过滤器)

typescript

运行

// src/filter/http-exception.filter.ts
import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common';
import { Response } from 'express';

@Catch(HttpException) // 捕获 HttpException 异常
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const status = exception.getStatus();
    const message = exception.getResponse();

    // 统一错误响应格式
    response.status(status).json({
      code: status,
      message,
      timestamp: new Date().toISOString(),
    });
  }
}

// 注册全局过滤器
@Module({
  providers: [
    {
      provide: APP_FILTER,
      useClass: HttpExceptionFilter,
    },
  ],
})
export class AppModule {}

3.9.3 源码逻辑(过滤器如何捕获异常)

过滤器执行逻辑在 @nestjs/core/filters 模块里:

  1. 异常抛出:控制器 / 服务抛出异常,NestJS 捕获这个异常。
  2. 匹配过滤器:按 “方法过滤器 → 控制器过滤器 → 全局过滤器” 的顺序匹配异常过滤器。
  3. 处理异常:匹配到过滤器后,调用 catch() 方法处理异常,返回自定义响应。
  4. 未匹配:如果没有匹配到过滤器,NestJS 返回默认的错误响应。

四、NestJS 请求生命周期(大白话版,必须懂)

一个 HTTP 请求从进入到返回,NestJS 会按以下顺序执行所有组件,看懂这个顺序,你就知道什么时候该用什么组件。

  1. 请求进来
  2. 全局中间件模块中间件
  3. 守卫(Guard) :判断是否允许请求
  4. 拦截器(Interceptor) :请求阶段
  5. 管道(Pipe) :校验 / 转换参数
  6. 控制器方法:处理业务逻辑
  7. 拦截器(Interceptor) :响应阶段
  8. 过滤器(Filter) :捕获异常(如果有)
  9. 返回响应给客户端

记忆口诀中 → 守 → 拦 → 管 → 控 → 拦 → 滤


五、NestJS 源码核心目录结构(大白话解读)

NestJS 源码在 @nestjs/core 包中,核心目录如下:

plaintext

@nestjs/core/
├── guards/           # 守卫相关逻辑
├── interceptors/     # 拦截器相关逻辑
├── middleware/       # 中间件相关逻辑
├── pipes/            # 管道相关逻辑
├── filters/          # 过滤器相关逻辑
├── injector/         # 依赖注入容器(NestContainer、Injector)
├── router/           # 路由注册、执行逻辑
├── scanner.ts        # 模块、装饰器扫描
├── nest-application.ts # 应用实例(NestApplication)
├── nest-factory.ts   # 应用创建工厂(NestFactory)
└── ...

5.1 NestFactory:应用的 “创建者”

  • 大白话NestFactory.create() 是 NestJS 应用的入口,负责创建应用实例。

  • 源码逻辑

    1. 读取根模块(AppModule)
    2. 扫描所有模块、控制器、服务
    3. 构建 IoC 容器
    4. 注册中间件、守卫、拦截器、管道、过滤器
    5. 绑定路由到 Express/Fastify
    6. 启动 HTTP 服务器

5.2 NestApplication:应用的 “管理者”

  • 大白话NestApplication 实例代表整个 NestJS 应用,负责管理所有组件、启动 / 停止服务器。

  • 核心方法

    • listen():启动服务器
    • close():停止服务器
    • use():注册全局中间件
    • useGlobalGuards():注册全局守卫
    • useGlobalInterceptors():注册全局拦截器
    • useGlobalPipes():注册全局管道
    • useGlobalFilters():注册全局过滤器

5.3 NestContainer:IoC 容器的 “核心”

  • 大白话NestContainer 是 NestJS 的 IoC 容器,存储所有模块、控制器、服务、提供者。

  • 核心功能

    • 注册 / 获取提供者
    • 解析依赖关系
    • 实例化对象
    • 管理对象生命周期

5.4 Scanner:模块的 “扫描器”

  • 大白话Scanner 负责扫描所有 @Module/@Controller/@Injectable 等装饰器,收集元数据。

  • 核心功能

    • 扫描模块依赖
    • 收集路由信息
    • 收集提供者信息
    • 检测循环依赖

六、NestJS 依赖注入源码核心逻辑(大白话拆解)

依赖注入是 NestJS 的灵魂,下面用大白话拆解源码核心逻辑。

6.1 依赖注入的 3 个核心角色

  1. 提供者(Provider) :被注入的对象(服务、值、工厂)
  2. 注入器(Injector) :负责创建、管理、传递提供者的对象
  3. 容器(Container) :存储所有提供者的 “仓库”

6.2 源码核心流程(简化版)

  1. 标记:用 @Injectable() 给类添加元数据,标记为可注入。
  2. 注册:模块扫描时,Scanner 把提供者注册到 NestContainer
  3. 解析:当需要注入提供者时,Injector 解析提供者的依赖(构造函数参数)。
  4. 实例化Injector 先实例化依赖,再实例化当前提供者。
  5. 缓存:默认单例,实例化后缓存到容器,下次直接取。

6.3 源码关键代码(简化版)

typescript

运行

// 简化版 NestContainer(源码核心逻辑)
class NestContainer {
  private providers = new Map(); // 存储提供者

  // 注册提供者
  registerProvider(token: any, provider: any) {
    this.providers.set(token, provider);
  }

  // 获取提供者实例
  getProvider(token: any) {
    const provider = this.providers.get(token);
    if (!provider) throw new Error('提供者不存在');

    // 如果是类,实例化(简化版)
    if (typeof provider === 'function') {
      const dependencies = Reflect.getMetadata('design:paramtypes', provider) || [];
      const instances = dependencies.map(dep => this.getProvider(dep));
      return new provider(...instances);
    }

    // 如果是值,直接返回
    return provider;
  }
}

七、NestJS 装饰器源码核心逻辑(大白话拆解)

装饰器是 NestJS 的 “语法糖”,下面拆解装饰器源码核心逻辑。

7.1 装饰器的本质

装饰器就是一个函数,接收类 / 方法 / 参数,给它们添加元数据(metadata),NestJS 扫描这些元数据来理解代码行为。

7.2 源码关键代码(简化版)

typescript

运行

// 简化版 @Controller 装饰器(源码核心逻辑)
function Controller(prefix: string) {
  return (target: any) => {
    // 给类添加元数据:path = prefix
    Reflect.defineMetadata('path', prefix, target);
    // 给类添加元数据:controller = true
    Reflect.defineMetadata('controller', true, target);
  };
}

// 简化版 @Get 装饰器
function Get(path: string) {
  return (target: any, propertyKey: string) => {
    // 给方法添加元数据:method = GET
    Reflect.defineMetadata('method', 'GET', target, propertyKey);
    // 给方法添加元数据:path = path
    Reflect.defineMetadata('path', path, target, propertyKey);
  };
}

7.3 元数据的作用

NestJS 扫描时,通过 Reflect.getMetadata() 获取这些元数据,知道:

  • 哪个类是控制器
  • 控制器的前缀是什么
  • 哪个方法处理 GET 请求
  • 方法的路由是什么

八、NestJS 常见问题大白话解答

8.1 为什么要用 NestJS,不用 Express?

  • Express 太自由,大型项目容易混乱;NestJS 强制规范,代码结构清晰。
  • Express 没有依赖注入,依赖耦合严重;NestJS 内置 DI,解耦、可测试。
  • Express 没有模块化,功能分散;NestJS 模块化,可复用、可扩展。
  • NestJS 内置中间件 / 守卫 / 拦截器 / 管道 / 过滤器,分层清晰,不用自己造轮子。

8.2 依赖注入和手动 new 有什么区别?

  • 手动 new:你自己创建对象,自己处理依赖,代码耦合,不可测试。
  • 依赖注入:框架帮你创建对象,自动处理依赖,代码解耦,可 Mock,可单测。

8.3 中间件、守卫、拦截器、管道、过滤器有什么区别?

  • 中间件:最早期执行,处理请求 / 响应,不能访问控制器 / 方法上下文。
  • 守卫:权限控制,返回 true/false,决定是否允许请求。
  • 拦截器:修改请求 / 响应,基于 RxJS,支持异步。
  • 管道:校验 / 转换参数,只处理参数。
  • 过滤器:捕获异常,统一错误响应。

8.4 NestJS 性能怎么样?

  • 底层跑在 Express/Fastify 上,性能和 Express/Fastify 几乎一致。
  • 依赖注入、装饰器等带来的性能损耗可以忽略不计。
  • 大型项目中,规范带来的维护收益远大于性能损耗。

九、总结:NestJS 到底好在哪?(大白话总结)

NestJS 就是 ** Node.js 后端的 “工程化标准”**:

  1. 模块化:代码不混乱,大型项目好维护。
  2. 依赖注入:解耦、可测试、不用管对象生命周期。
  3. 装饰器驱动:代码简洁、可读性强。
  4. 分层架构:中间件 / 守卫 / 拦截器 / 管道 / 过滤器,职责清晰。
  5. 底层兼容:Express/Fastify 生态随便用。
  6. 企业级:适合大型项目、团队协作、生产环境。

如果你是 Node.js 后端开发者,尤其是做大型项目,NestJS 绝对是首选。