Node.js_NestJS_系统学习计划

Node.js + NestJS 系统学习计划从零搭建完整 TypeScript Node 工程 模块化体系 · 异步编程 · 环境变量管理 · 工程化实战学习周期:5 天(每天 1 个核心模块) 文档版本:v1.0 | 2026-06-17一、学习总览1.1 学习目标掌握 Node.js 运行时核心机制(事件循环、模块加载、异步 I/O)熟练使用 TypeScript 编写 Node 工程,理解 tsconfig 关键配置项掌握 NestJS 框架核心理念:Controller、Service、Module、DI(依赖注入)、Pipe从零搭建一个具备统一响应体、参数校验、环境配置的完整工程建立模块化拆分思维,具备独立设计中型后端项目架构的能力1.2 前置环境要求操作系统:Windows / macOS / LinuxNode.js ≥ 18.x(推荐 LTS 版本)包管理器:npm 或 pnpm(推荐 pnpm)编辑器:VSCode(推荐安装 ESLint、Prettier 插件)终端工具:Windows Terminal / iTerm21.3 五天学习路线总览

天数

核心主题

关键产出

预计时长

Day 1

Nest 环境搭建与项目初始化

可运行的 NestJS 脚手架工程

4-5h

Day 2

Controller 控制器与路由

完整的 RESTful API 控制器

4-5h

Day 3

Service 分层与依赖注入

分层清晰的业务模块

4-5h

Day 4

统一返回体封装与周复盘

标准化响应中间件 + 复盘文档

4-5h

Day 5

参数校验与 Pipe 管道

完整的参数校验体系

4-5h

二、Node.js 核心基础知识储备在正式进入 NestJS 框架之前,需要确保对 Node.js 的以下核心概念有清晰认知。这部分作为所有 Day 的前置知识,建议在 Day 1 开始前花 1-2 小时快速过一遍。2.1 事件循环与异步 I/ONode.js 采用单线程事件循环模型,通过 libuv 实现非阻塞 I/O。理解以下概念至关重要:Event Loop 六个阶段:timers → pending → idle → poll → check → close微任务(Microtask):Promise.then、process.nextTick 优先于宏任务执行宏任务(Macrotask):setTimeout、setInterval、setImmediate、I/O 回调阻塞与非阻塞:CPU 密集型操作会阻塞事件循环,应通过 Worker Threads 或子进程分流关键认知:Node.js 的「异步」本质是把耗时操作交给系统/libuv 线程池处理,主线程继续执行后续代码,完成后再回调通知。2.2 模块化体系Node.js 存在两套模块系统,NestJS 项目基于 ES Modules 理念但实际使用 CommonJS 编译:CommonJS(CJS):Node.js 原生支持,使用 require/module.exports。编译后的 TS 默认输出 CJS。ES Modules(ESM):现代标准,使用 import/export。需要在 package.json 中设置 "type": "module" 或使用 .mjs 扩展名。TypeScript 模块编译关键点:tsconfig.json 中 "module" 选项控制输出格式(commonjs / esnext / node16)"moduleResolution" 决定模块解析策略(node / bundler / node16)NestJS 默认使用 CJS 输出,搭配 "module": "commonjs" 和 "moduleResolution": "node"2.3 环境变量管理生产级项目必须将敏感配置(数据库地址、密钥、API Key)与代码分离。核心方案:dotenv 库:将 .env 文件中的键值对注入 process.env@nestjs/config:NestJS 官方配置模块,基于 dotenv 封装,支持配置校验ConfigService:通过依赖注入在任意模块中安全读取环境变量环境变量加载优先级(从高到低):系统环境变量(CI/CD 注入).env.{环境}.local 文件(如 .env.production.local).env.{环境} 文件(如 .env.development).env 文件(默认配置)安全红线:.env 文件必须加入 .gitignore,绝不允许提交到版本库。三、Day 1 — Nest 环境搭建与项目初始化3.1 学习目标理解 NestJS 框架设计哲学(约定优于配置、Angular 式架构)掌握 CLI 工具创建标准化项目理解项目目录结构与各文件职责成功运行项目并访问默认接口3.2 落地步骤Step 1:全局安装 NestJS CLInpm install -g @nestjs/cli验证安装:nest --versionStep 2:创建项目nest new my-nest-app # 选择包管理器(推荐 pnpm)CLI 会自动生成标准目录结构并完成依赖安装。Step 3:理解目录结构核心文件说明:

文件/目录

职责说明

src/main.ts

应用入口,创建并启动 Nest 应用实例

src/app.module.ts

根模块,所有模块的注册入口

src/app.controller.ts

根控制器,处理 HTTP 请求路由

src/app.service.ts

根服务层,封装业务逻辑

src/app.controller.spec.ts

控制器单元测试文件

test/

端到端测试(e2e)目录

nest-cli.json

Nest CLI 配置文件

tsconfig.json

TypeScript 编译配置

Step 4:运行项目# 开发模式(热重载) npm run start:dev # 生产模式 npm run build npm run start:prod访问 http://localhost:3000 确认返回 "Hello World!" 即表示环境搭建成功。Step 5:初始化 Git 仓库git init git add . git commit -m "feat: init nest project"3.3 核心概念速记Module(模块):组织代码的基本单元,通过 @Module() 装饰器声明Controller(控制器):处理 HTTP 请求,通过 @Controller() 装饰器绑定路由Provider(提供者):可注入的类(Service、Repository 等),通过 @Injectable() 标记3.4 Day 1 校验清单

序号

校验项

完成状态

1

nest --version 命令正常输出版本号

□ 未完成

2

nest new 创建的项目目录结构完整

□ 未完成

3

npm run start:dev 启动成功,浏览器访问 localhost:3000 返回 Hello World!

□ 未完成

4

能说出 main.ts、app.module.ts、app.controller.ts、app.service.ts 各自职责

□ 未完成

5

tsconfig.json 中 target、module、outDir 配置项含义清晰

□ 未完成

6

已完成 Git 初始化并提交首次 commit

□ 未完成

四、Day 2 — Controller 控制器与路由系统4.1 学习目标掌握 @Controller、@Get、@Post 等装饰器的使用理解路由参数获取方式(路径参数、查询参数、请求体)能独立编写具备完整 CRUD 路由的控制器4.2 落地步骤Step 1:创建业务模块# 使用 CLI 快速生成模块 + 控制器 + 服务 nest g resource users # 选择 REST API,自动生成 users 模块三件套Step 2:编写 GET 请求// users.controller.ts @Controller("users") export class UsersController { @Get() // GET /users findAll() { return "返回所有用户列表"; } @Get(":id") // GET /users/:id findOne(@Param("id") id: string) { return `返回 ID 为 ${id} 的用户`; } }Step 3:编写 POST 请求@Post() // POST /users create(@Body() body: CreateUserDto) { return `创建用户:${body.name}`; }Step 4:掌握请求参数获取方式

装饰器

用途

示例

@Param()

路径参数

GET /users/:id → @Param("id")

@Query()

查询参数

GET /users?page=1 → @Query("page")

@Body()

请求体

POST JSON body → @Body()

@Headers()

请求头

获取 Authorization 等

@Req() / @Res()

原始请求/响应对象

需要底层操作时使用

Step 5:HTTP 方法全覆盖练习在 UsersController 中补全以下方法:@Get() — 获取列表@Get(":id") — 获取单个@Post() — 创建@Put(":id") — 更新@Delete(":id") — 删除@Patch(":id") — 部分更新练习目标:用 Postman 或 Thunder Client 逐一测试每个接口,确保路由、方法、参数全部正确。4.3 Day 2 校验清单

序号

校验项

完成状态

1

能通过 nest g resource 快速生成模块

□ 未完成

2

UsersController 包含完整的 GET/POST/PUT/DELETE 方法

□ 未完成

3

能用 @Param 获取路径参数,用 @Query 获取查询参数,用 @Body 获取请求体

□ 未完成

4

Postman 测试所有接口均正常响应

□ 未完成

5

理解 @Controller("users") 中的前缀如何影响所有子路由

□ 未完成

6

能解释 Nest 的请求生命周期:Request → Middleware → Guard → Interceptor → Pipe → Controller

□ 未完成

五、Day 3 — Service 分层与依赖注入5.1 学习目标理解 NestJS 分层架构思想(Controller → Service → Repository)掌握依赖注入(DI)原理与 @Injectable 装饰器学会 Module 模块拆分与跨模块引用5.2 落地步骤Step 1:编写 UsersService// users.service.ts @Injectable() export class UsersService { private users = [ { id: 1, name: "张三", email: "zhang@test.com" }, { id: 2, name: "李四", email: "li@test.com" }, ]; findAll() { return this.users; } findOne(id: number) { return this.users.find(u => u.id === id); } create(dto: CreateUserDto) { const user = { id: Date.now(), ...dto }; this.users.push(user); return user; } }Step 2:Controller 注入 Service@Controller("users") export class UsersController { constructor(private readonly usersService: UsersService) {} // Nest 自动注入 UsersService 实例 @Get() findAll() { return this.usersService.findAll(); } }关键理解:NestJS 的 DI 容器在 Module 注册 Provider 后,会自动解析构造函数中的依赖关系,无需手动 new 实例。Step 3:Module 模块拆分将 users 功能封装为独立模块:// users.module.ts @Module({ controllers: [UsersController], providers: [UsersService], exports: [UsersService], // 允许其他模块使用 }) export class UsersModule {}在根模块中引入:// app.module.ts @Module({ imports: [UsersModule], }) export class AppModule {}Step 4:跨模块依赖注入新建 orders 模块,演示跨模块调用:// orders.module.ts @Module({ imports: [UsersModule], // 引入 UsersModule controllers: [OrdersController], providers: [OrdersService], }) export class OrdersModule {}在 OrdersService 中注入 UsersService:@Injectable() export class OrdersService { constructor(private readonly usersService: UsersService) {} // 可直接调用 usersService 的方法 }Step 5:理解 DI 三种注入方式构造器注入(推荐):在 constructor 中声明依赖,Nest 自动注入属性注入:使用 @Inject() 装饰器标记属性工厂注入:使用 useFactory 动态创建 Provider架构原则:Controller 只做请求转发(接收参数 → 调用 Service → 返回结果),所有业务逻辑集中在 Service 层。5.3 Day 3 校验清单

序号

校验项

完成状态

1

UsersService 封装了完整的 CRUD 业务逻辑

□ 未完成

2

UsersController 通过构造函数注入 UsersService,无手动 new

□ 未完成

3

UsersModule 正确声明了 controllers、providers、exports

□ 未完成

4

AppModule 成功引入 UsersModule,项目正常运行

□ 未完成

5

能创建 OrdersModule 并跨模块注入 UsersService

□ 未完成

6

能解释 Provider、Injectable、Module 三者的关系

□ 未完成

六、Day 4 — 统一返回体封装与周复盘6.1 学习目标掌握 NestJS Interceptor(拦截器)机制实现全局统一响应格式 {code, data, message}完成前四天的系统性复盘,沉淀知识体系6.2 落地步骤Step 1:定义统一响应体结构// common/dto/response.dto.ts export class ResponseDto<T> { code: number; message: string; data: T; constructor(code: number, message: string, data: T) { this.code = code; this.message = message; this.data = data; } static success<T>(data: T, message = "success") { return new ResponseDto(200, message, data); } static error(message: string, code = 500) { return new ResponseDto(code, message, null); } }Step 2:创建全局响应拦截器// common/interceptors/response.interceptor.ts @Injectable() export class ResponseInterceptor implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler) { return next.handle().pipe( map((data) => ({ code: 200, message: "success", data: data ?? null, })), ); } }Step 3:全局注册拦截器// main.ts async function bootstrap() { const app = await NestFactory.create(AppModule); app.useGlobalInterceptors(new ResponseInterceptor()); await app.listen(3000); }Step 4:创建全局异常过滤器// common/filters/http-exception.filter.ts @Catch() export class AllExceptionFilter implements ExceptionFilter { catch(exception: any, host: ArgumentsHost) { const ctx = host.switchToHttp(); const response = ctx.getResponse(); const status = exception.getStatus?.() ?? 500; response.status(status).json({ code: status, message: exception.message || "服务器内部错误", data: null, }); } }在 main.ts 中注册:app.useGlobalFilters(new AllExceptionFilter());Step 5:验证统一返回格式正常响应示例:{ "code": 200, "message": "success", "data": [{ "id": 1, "name": "张三" }] }异常响应示例:{ "code": 404, "message": "用户不存在", "data": null }6.3 环境变量配置实战# 安装配置模块 npm install @nestjs/config创建 .env 文件:DB_HOST=localhost DB_PORT=3306 DB_NAME=my_app APP_PORT=3000 JWT_SECRET=your_secret_key在 AppModule 中注册:@Module({ imports: [ ConfigModule.forRoot({ isGlobal: true, // 全局可用 envFilePath: ".env", // 指定文件路径 }), ], })在 Service 中读取:@Injectable() export class AppService { constructor(private configService: ConfigService) {} getDbHost() { return this.configService.get("DB_HOST"); } }.env 文件必须加入 .gitignore!创建 .env.example 作为模板提交到仓库。6.4 Day 4 校验清单

序号

校验项

完成状态

1

所有正常接口返回统一的 {code: 200, message, data} 格式

□ 未完成

2

所有异常接口返回 {code: 状态码, message: 错误信息, data: null}

□ 未完成

3

Interceptor 和 ExceptionFilter 均已全局注册

□ 未完成

4

.env 文件配置了数据库和应用配置

□ 未完成

5

ConfigModule 设置为 isGlobal,任意 Service 可通过 ConfigService 读取

□ 未完成

6

.env 已加入 .gitignore,.env.example 已提交

□ 未完成

6.5 本周复盘框架完成以上 4 天学习后,按以下框架进行系统性复盘:

复盘维度

具体内容

知识点梳理

列出每天学到的 3 个最核心概念,用自己的话解释

代码产出统计

统计本周编写的文件数、代码行数、API 接口数

踩坑记录

记录遇到的 3 个以上 Bug 及解决方案

架构认知升级

对比学习前后对后端项目结构的理解差异

薄弱环节标记

标记尚未完全理解的概念,列入下周攻坚清单

下周规划

制定 Day 5 及后续扩展学习方向(数据库、JWT 鉴权等)

七、Day 5 — 参数校验与 Pipe 管道7.1 学习目标掌握 class-validator 和 class-transformer 进行 DTO 参数校验理解 NestJS Pipe 管道机制(校验管道、转换管道)实现全局校验管道,自动拦截非法请求7.2 落地步骤Step 1:安装校验依赖npm install class-validator class-transformerStep 2:编写带校验装饰器的 DTO// users/dto/create-user.dto.ts import { IsString, IsEmail, IsNotEmpty, MinLength } from "class-validator"; export class CreateUserDto { @IsString({ message: "name 必须是字符串" }) @IsNotEmpty({ message: "name 不能为空" }) @MinLength(2, { message: "name 至少 2 个字符" }) name: string; @IsEmail({}, { message: "email 格式不正确" }) email: string; @IsString() @MinLength(6, { message: "密码至少 6 位" }) password: string; }Step 3:启用全局校验管道// main.ts import { ValidationPipe } from "@nestjs/common"; app.useGlobalPipes(new ValidationPipe({ whitelist: true, // 自动过滤 DTO 未定义的字段 forbidNonWhitelisted: true, // 传入未定义字段直接报错 transform: true, // 自动类型转换(string → number 等) }));Step 4:理解 Pipe 执行时机NestJS 请求处理流程中,Pipe 在 Controller 方法执行前运行:Request → Middleware → Guard → Interceptor(前) → Pipe(校验) → Controller → Interceptor(后)Step 5:自定义 Pipe 实践// 自定义转换管道示例 @Injectable() export class ParseIntIdPipe implements PipeTransform<string, number> { transform(value: string): number { const val = parseInt(value, 10); if (isNaN(val)) { throw new BadRequestException("ID 必须是有效数字"); } return val; } } // 使用 @Get(":id") findOne(@Param("id", ParseIntIdPipe) id: number) { return this.usersService.findOne(id); }Step 6:校验效果验证发送非法请求测试:POST /users { "name": "", "email": "not-email" } // 期望返回: { "code": 400, "message": [ "name 不能为空", "name 至少 2 个字符", "email 格式不正确", "密码至少 6 位" ], "data": null }ValidationPipe 的 transform: true 可以自动将路径参数、查询参数从 string 转换为目标类型,省去手动 parseInt 的麻烦。7.3 Day 5 校验清单

序号

校验项

完成状态

1

class-validator 和 class-transformer 安装成功

□ 未完成

2

CreateUserDto 添加了完整的校验装饰器(IsString、IsEmail、MinLength 等)

□ 未完成

3

全局 ValidationPipe 已注册,whitelist + forbidNonWhitelisted + transform 全部开启

□ 未完成

4

发送非法参数时返回 400 错误及具体校验失败信息

□ 未完成

5

能编写自定义 Pipe(ParseIntIdPipe)并应用到路由参数

□ 未完成

6

能说出 Pipe 在 Nest 请求生命周期中的位置和作用

□ 未完成

八、整体学习复盘与进阶路线8.1 五天知识图谱回顾完整学习路径,以下是各天核心知识点的关联关系:Day 1 环境搭建 → 理解 NestJS 项目骨架(Module、Controller、Service 三大件)Day 2 Controller → 掌握请求入口(路由、参数、HTTP 方法)Day 3 Service + DI → 掌握业务分层(逻辑封装、依赖注入、模块拆分)Day 4 统一返回体 → 掌握工程化规范(拦截器、异常处理、环境配置)Day 5 参数校验 → 掌握防御编程(DTO 校验、管道机制、类型转换)8.2 核心概念关系图Module(模块组织) ├── Controller(接收请求、路由分发) │ └── 调用 Service ├── Service(业务逻辑、数据处理) │ └── 使用 Provider / Repository ├── Pipe(参数校验、类型转换) ├── Interceptor(响应拦截、格式统一) ├── ExceptionFilter(异常捕获、错误格式化) └── ConfigModule(环境变量、配置管理)8.3 进阶学习路线(后续 2-4 周)

周次

学习主题

关键产出

第 2 周

TypeORM / Prisma 数据库集成 Entity 定义、CRUD 操作 数据库迁移

完整的数据库增删改查 API

第 3 周

JWT 鉴权与守卫(Guard) @nestjs/jwt + passport 角色权限控制

登录注册 + Token 鉴权体系

第 4 周

Swagger 文档自动生成 文件上传、定时任务 Docker 容器化部署

可部署的生产级完整项目

8.4 自我评估量表在完成全部 5 天学习后,对以下能力维度进行自评(1-5 分):

能力维度

评估要点

自评分

Node.js 基础

事件循环、模块系统、异步 I/O 理解程度

___/5

TypeScript 运用

类型定义、接口、装饰器在实际项目中的使用

___/5

NestJS 框架

Module/Controller/Service/DI 体系掌握程度

___/5

工程化规范

统一响应体、异常处理、环境配置、参数校验

___/5

独立开发能力

能否从零独立搭建一个中等规模的 NestJS 项目

___/5

8.5 常见问题 FAQQ:Controller 里能不能直接写业务逻辑?A:技术上可以,但不推荐。Controller 只负责「接收请求 → 调用 Service → 返回结果」,保持薄控制器原则有利于测试和维护。Q:什么时候用 Interceptor,什么时候用 Middleware?A:Interceptor 能感知 NestJS 上下文(可访问 Controller 元数据),适合做响应转换、日志记录;Middleware 更接近 Express,适合做通用的请求预处理(如 CORS、body-parser)。Q:ValidationPipe 的 whitelist 和 forbidNonWhitelisted 有什么区别?A:whitelist 默默过滤掉 DTO 未定义的字段;forbidNonWhitelisted 在此基础上直接抛 400 错误,更严格。建议两者同时开启。Q:ConfigModule 设置 isGlobal: true 后还需要在子模块 imports 里引入吗?A:不需要。isGlobal 为 true 时,ConfigService 在任意模块都可直接注入使用。

更多推荐