定位:本篇是全专栏的结语,不引入新概念。按阶段逐段小结:每个阶段讲了什么、真实项目里落成了什么样、读完该带走什么。最后给一份跨阶段的自检清单。适合两种读法:跟着读完的同学用来收束,还没读的同学先看这份地图再决定从哪进。
一、阶段小结:认识与骨架
这个阶段回答的是"一个 Nest 应用静止时长什么样"。从框架选型对比切入,然后把三块静态结构立起来:Controller 是壳,只声明路由和参数;Provider 是"登记进容器的东西",业务逻辑住在这里;Module 决定"装哪棵树"------谁 import 谁、谁把谁装配起来。
其中花了两篇把"依赖注入"这个后端黑话拆给前端:它就是你在 React 里写 Provider/Context/hooks 时早就在用的"声明依赖、框架接线",只是 Nest 把接线时机搬到了启动期。三篇分工讲透:概念(IoC/DI/DLP 是什么)、机制(token 注册 → 反射元数据 → 容器实例化的解析链路)、动机(为什么不用 new------依赖的来源不该写死在使用处)。
真实项目的落地面貌:五种 token 形态各就各位------类 token 自动推断、APP_CONFIG 用 useValue 装配置单例、AUTH_TOKENS 用 useFactory 派生窄 token、APP_GUARD/APP_PIPE 系统槽位注入全局组件;同一条依赖链里,纯函数直接 import、数据库连接进容器、配置走注入,三种依赖三种处理。
这个阶段带走一句:Nest 的静态骨架 = 一棵"模块装 provider、provider 互相注入"的树,装饰器只是声明,容器才是接线员。
二、阶段小结:请求管线
这个阶段回答"一个请求进来会发生什么",而且是按真实执行顺序讲的:总览先给一张时序图,后面每篇往图上钉一颗钉子------Middleware → Guards → Pipes → Interceptors → Filters,再用 ExecutionContext 和自定义装饰器补齐"跨切面组件怎么看宿主、怎么读暗号"。
各层的职责边界一次钉死:Middleware 改环境(读不到路由元数据,所以鉴权不归它);Guards 管"放不放行";Pipes 管"数据归一与校验";Interceptors 管成功路径上"流的前后";Filters 管异常路径的收口。判断"该用哪个"只看一层问题:发生在路由确定之前还是之后、是数据问题还是权限问题、是成功路径还是异常路径。
真实项目的落地面貌,是这个阶段最厚的一批实证:
- RequestContextMiddleware :复用/生成 requestId、回写响应头,再用
AsyncLocalStorage把上下文播种成"隐形通道",守卫到过滤器全管线都能读------深处 service 不再需要一层层传 Request; - 两条全局管道分家 :
TrimBodyPipe走APP_PIPE、ValidationPipe 留useGlobalPipes,注册分家后"先归一化后校验"的顺序靠注册时序链保证,堵住纯空白串骗过校验的洞; - AuthGuard + 暗号机制 :
@Public()/@RequireAdmin()只写元数据不干活,守卫用 Reflector 读,方法级优先类级兜底; - LoggingInterceptor + AllExceptionsFilter:日志五段各自来源可考、错误契约(code 有限分类 + 预填决策字段)让"错误即数据"。
还有一条贯穿的排查心法:用日志盲区反推抛错位置------守卫 401 零痕迹、管道 400 有 warn、拦截器根本没被调用,有无日志本身就是证据。
这个阶段带走一句:请求管线五种组件不是五个 API,是五种职责边界;按执行顺序读一遍,等于在脑内跑了一遍请求。
三、阶段小结:应用生命周期
管线讲的是"请求怎么活",这一篇讲"应用实例怎么活":onModuleInit / onBootstrap / onShutdown 三个钩子,以及最容易被忽略的**"构造时刻 vs 钩子时刻"之别**------依赖没就绪的活不能写在构造器里,要等钩子。
真实项目的四个落点各代表一种形态:配置校验用 onModuleInit 做 fail-fast 拒绝启动(坏配置活不过启动期);启动快照钩子用日志顺序自证时序;数据库服务用类 provider 保住钩子、OnApplicationShutdown 关连接停机;策略注册器演示"启动期一次性副作用"。决策线也钉死了:作用域线和可用性线是两种哲学------有的活该活到应用死,有的活该挂了也能重试。
这个阶段带走一句:初始化写在钩子里,不写在构造器里;停机要有人负责,连接要有人关。
四、阶段小结:DI 与模块进阶
难度最高的一段,但组织方式始终是"问题驱动"------每篇回答一个具体问题,API 只是答案:
- 自定义 Provider 四形态,答"这个依赖值不值得进容器":类速记、useValue、useFactory、useClass 各有主场,形态本身就是语义;
- 动态模块与 forRoot + @Global 落地,答"配置从哪来、谁拍板":ConfigModule/VectorDbModule 两个真实 forRoot 逐行对读,组合根(AppModule)是唯一拍板处;@Global 装饰器退役、isGlobal 参数上岗------决策权回到调用方;
- 循环依赖与 forwardRef ,答"环了怎么办":真实项目零 forwardRef,靠 core 纯函数库消掉最易成环的互指------最好的解环是不成环;
- 异步 Provider,答"初始化是异步的怎么办":项目两次绕开它(现连便宜 + 懒建缓存),触发信号清单一条没亮------知道什么时候不用,和会用一样重要;
- 作用域 + Durable,答"一份实例活多久":默认单例是 Node 的恩惠,REQUEST 是账单;真正"每请求带上下文"的诉求用 ALS 解决;多租户若真到来,更可能走 ALS + Map 而非 durable 子树;
- ModuleRef + 懒加载 ,答"想运行时拿实例怎么办":四端点复刻 demo 证机制(查缓存/现造/无中生有/严格模式),IndexingModule 真路径触发落地,踩实 NodeNext 动态 import 必须显式
.js的编译期大坑。
这个阶段的诚实口径最密集:ModuleRef/Durable 在真实项目里都是"机制演示非生产",零使用的地方讲清为什么零------这批内容的价值不在"你也该用",而在"你知道有这扇门、以及门后是什么代价"。
这个阶段带走一句:DI 进阶的每一招都是账单------先问"我真的有这个诉求吗",再掏工具。
五、跨阶段自检:五道题
五道题各考一个阶段的核心,能脱稿答出,说明二十六篇真正消化了:
- 骨架:拿到一个新依赖,判断"要不要进容器"的两族判据是什么?同一条依赖链里"注入 / 直接 import / 动态 import"三种处理怎么选?
- 管线:一个请求进来,守卫返回 401,后面哪些组件根本不会执行?日志上能看出什么、看不出什么?
- 管线 :两条全局管道一条走
APP_PIPE、一条走useGlobalPipes,注册分家后"先归一化后校验"的顺序靠什么保证? - 生命周期:为什么初始化不能写在构造器里?"配置校验拒绝启动"和"连接挂了还能重试"分别是哪种哲学?
- DI 进阶:多租户场景,你会在"REQUEST scope + durable"和"ALS + Map"之间怎么选?真实项目的现役答案是什么、为什么?
专栏正文至此全部完结。感谢读到这里------愿这张地图帮你把前端经验折算成后端速度,少走我们走过的弯路。