大家好,我是程序员柏风,AI 最全的 Vibecoding 学习地图 http://coderoadmap.cn 作者。
NestJS 是什么
这一课你将能做到
- 用人话说清楚 NestJS 比原生 Express 多了什么:Module 分包、依赖注入容器、装饰器路由
- 对照本站 Spring Boot,说出
@Controller/@Injectable/ Guard / Pipe 分别对应谁 - 给出「什么项目选 Nest、什么项目继续 Express、什么交给 Spring Boot」的判断依据
为什么要学
你要做一个刷题平台后端:题库管理、提交答案、自动判分、错题本、排行榜。用 Express 从 app.get("/questions") 起步很轻快,但功能一多问题就来了:30 个路由文件里各自 new XxxService()、业务规则散落在回调里、单元测试想替换掉数据库全靠手动重写。代码能不能维护,取决于作者当天的自觉。
NestJS 的解法是:在 Node.js + TypeScript 上套一层企业级骨架——强制按 Module 分包、用依赖注入容器装配 Service、用装饰器声明路由和横切逻辑。每个类放哪、谁能注入谁,框架都帮你管起来。
本站生产环境的主 API 仍是 Spring Boot。所以学 Nest 对本站读者有两个现实意义:一是全栈 TypeScript 团队或 BFF(Backend for Frontend,面向前端的聚合层)场景确实会用到;二是它和 Spring Boot 的分层几乎一一对应,学它等于换一种语言把 Controller-Service-Repository 这套架构思想再练一遍,理解会更深。
先建立图像
一次请求在 Nest 内部的流水线:
HTTP 请求
→ Middleware(中间件,Express 风格)
→ Guard(守卫:有没有权限进来?)
→ Interceptor(拦截器:方法前后织入,可改返回)
→ Pipe(管道:参数转换与校验)
→ Controller(控制器:HTTP 适配,不写业务)
→ Service(服务:业务规则与编排)
→ Repository / 外部 API(持久化与第三方调用)
Module 在旁边负责「装配清单」:这个包里有哪些 Controller、哪些 Service、哪些 Service 允许别人用;DI 容器按构造器声明的类型自动把实例塞进去。
Express 与 Nest 对比:
| 对比项 | Express | NestJS |
|---|---|---|
| 项目结构 | 自由发挥 | Module / Controller / Provider 强制分层 |
| 语言 | 可选 TypeScript | 默认 TypeScript 优先 |
| 依赖获取 | 手写 require / new | IoC 容器按构造器注入 |
| 横切逻辑 | 手写中间件 | Guard / Interceptor / Pipe 分工 |
| 整体感觉 | 轻量 HTTP 胶水 | Spring / Angular 风格的完整骨架 |
与 Spring Boot 速查表:
| Spring Boot | NestJS |
|---|---|
@RestController | @Controller() |
@Service | @Injectable() |
@Autowired | 构造器参数注入(也可用 @Inject) |
HandlerInterceptor / AOP | NestInterceptor |
| Spring Security 过滤器链 | CanActivate Guard |
@Valid + Bean Validation | ValidationPipe + class-validator |
@ControllerAdvice | 全局 ExceptionFilter |
application.yml + @Value | ConfigModule + ConfigService |
底层默认跑在 Express 之上(也可以切换到 Fastify)。你启动的还是 Node 进程,改变的是代码的组织方式,不是运行时。
跟着做
步骤 1:确认前置环境
打开终端执行:
node -v
npm -v
NestJS 10 建议 Node.js 18 或 20 以上的 LTS 版本。版本过低先升级 Node。本课程默认你已经写过基础的 Express 和 TypeScript,能看懂接口、类与泛型。
步骤 2:浏览官方文档的 Introduction
打开 docs.nestjs.com,阅读 Introduction 一节即可,重点留意三个词:TypeScript、modular(模块化)、dependency injection(依赖注入)。不用细读长代码,先混个脸熟。
步骤 3:读懂一个真实控制器长什么样
下面是刷题平台的题库控制器,后续课程会亲手把它跑起来,现在先逐行理解:
import { Controller, Get, Param } from "@nestjs/common";
import { QuestionsService } from "./questions.service";
// 人话:这个类负责处理 /questions 开头的请求
@Controller("questions")
export class QuestionsController {
// 人话:我需要一个 QuestionsService,别让我自己 new
constructor(private readonly questions: QuestionsService) {}
// 人话:GET /questions 时调用这个方法
@Get()
findAll() {
return this.questions.findAll();
}
// 人话:GET /questions/123 时,把 123 作为 id 传入
@Get(":id")
findOne(@Param("id") id: string) {
return this.questions.findOne(Number(id));
}
}
装饰器是写在类和方法上的「标签」,编译时以元数据形式保留;运行时 Nest 读取这些标签,自动注册路由、解析依赖。你几乎不再手写 app.get(...),而是「定义类、贴标签、写方法」。
步骤 4:写下三句选型结论
在笔记本上写下(建议用自己的话改写):
- 本站核心业务 API(题库、判分、支付等企业系统)→ 继续 Spring Boot。
- 全栈 TS 团队的中型 API,或给前端做 BFF 聚合层 → 选 NestJS。
- 一次性脚本、极简原型、极轻量的 webhook 服务 → Express 足够。
步骤 5:在路线图上找到它的位置
NestJS 处在 Node.js 路线图里「框架」这一进阶节点上,前置知识是 Node 基础与 TypeScript。本门课把这个节点展开成 12 节可跟做的精讲:从装环境到交付一个带校验、鉴权、测试的刷题平台 API。
讲清楚要点
- 大项目需要强制约定:Nest 用 Module 明确分包边界,而不是靠文件夹命名的默契。
- 测试需要可替换的依赖:业务类标记为
@Injectable并由容器注入,单测时可以轻松换成 mock 实现。 - 路由需要可扫描的声明:
@Get、@Post等装饰器让路由与类方法绑定,和 Spring MVC 的写法思路一致。 - 底层仍是 Node HTTP:你学过的 Express 中间件、异步流、事件循环知识全部有效,Nest 只是上层骨架。
- 本站语境下重点是模式迁移:Controller / Service / Guard / Pipe 与 Spring 概念一一对应,学会对比比背 API 更重要。
- 性能适配器可选:入门用默认 Express 适配器;真遇到吞吐瓶颈,再评估 Fastify 适配器的切换成本。
你可能会懵的地方
-
NestJS 是不是另一个 Express? 不是。它默认以 Express 为 HTTP 引擎,但在上面加了 DI 容器、模块系统和 Guard/Pipe/Interceptor。类比:Express 是发动机,Nest 是包含底盘和电路的整车。
-
装饰器难不难?要不要自己造? 初学者在入门阶段只会用官方提供的
@Controller、@Get、@Injectable就够了;自定义装饰器是后面课程的内容,不需要一上来就研究原理。 -
听说它和 Angular 很像? 作者确实受 Angular 启发,Module、DI、装饰器风格接近。做过 Angular 的人会上手很快;没做过也完全不影响学习。
-
必须先会 Spring 才能学 Nest 吗? 不必。对照 Spring 只是帮助有 Java 基础的读者加速理解;会 Express 加 TypeScript 就能开始。
-
DI 容器里到底装了什么? 默认情况下,每个被注册的 Provider 在整个应用中是单例,容器启动时(或首次使用时)创建实例,解析控制器构造器时按类型取出并注入。
错法对照
| 错法 | 问题 | 正解 |
|---|---|---|
| 把 Nest 理解为「用来淘汰 Express 的新运行时」 | 概念错误,排查方向会偏 | 它是 Node 之上的组织框架,底层常仍是 Express |
在 Controller 里写业务并 new QuestionsService() | 绕过容器,难以测试和替换 | 构造器注入 + 在 Module 注册 |
| 只抄装饰器、不懂 Module 装配 | 启动必报「无法解析依赖」 | 先学会 providers / imports / exports |
| 认为会了 Nest 就该把本站 Java 全部重写 | 脱离团队语言与生态实际 | 按场景选型,Spring 仍是本站主栈 |
| 一上来就纠结 Express 还是 Fastify | 在不重要的点上耗时 | 默认适配器入门,有性能数据再切换 |
卡点急救
- 看文档全是术语读不下去:先抓住「一个类管路由、一个类管业务、一张清单把它们组装起来」这三句话,术语会在后续课程逐个落地。
- 担心 TypeScript 不够好:能定义 interface、给函数参数标类型、看懂泛型即可开始;框架代码本身就是最好的 TS 教材。
- 不确定项目适不适合 Nest:问三个问题——路由是否超过十个、是否多人协作、是否需要自动化测试。三个都答「是」,Nest 的收益就很明显。
面试常问
-
NestJS 相比 Express 的核心优势是什么? 开箱即用的模块化架构、依赖注入、Guard/Interceptor/Pipe 等标准化横切能力;代价是更多概念和样板代码。小项目 Express 更轻快,中大型团队项目 Nest 更可维护。
-
NestJS 的依赖注入和 Spring 的 IoC 是一回事吗? 思想一致:类不主动创建依赖,而是声明需求、由容器注入。差别在于 Nest 主要靠 TypeScript 构造器类型与装饰器元数据,且模块可见性需要显式 exports,不像 Spring 靠包扫描默认全局可见。
-
NestJS 默认基于哪种 HTTP 库? 默认是 Express,通过平台适配器封装;也可以用
@nestjs/platform-fastify切换到 Fastify,业务代码基本不变。
自测三问
- 一次请求进入 Nest 后,Guard、Pipe、Controller、Service 的先后顺序是什么?
@Injectable大致对应 Spring 的哪个注解?它解决什么问题?- 什么场景下你仍然会选择 Express 而不是 NestJS?
小结一句话
NestJS 是 TypeScript 语言里带模块化和依赖注入的企业级 Node 后端框架,骨架对标 Spring,底层仍是 Node。
延伸
- NestJS 官方文档 Introduction
- First steps(官方入门步骤)
- 下一课预告:用 Nest CLI 创建刷题平台项目
quiz-api,认清目录结构并跑通第一个接口。