
目錄前言一、NestJS 概念二、一個(gè)請求在 NestJS 中怎么走請求流程??????三、NestJS 運(yùn)行架構(gòu)圖簡圖四、NestJS 的核心機(jī)制必須記住??????????五、NestJS 核心成員全量速覽表建議收藏六、重點(diǎn)核心成員「逐個(gè)突破」1、Module結(jié)構(gòu)與邊界??????????2、Provider一切可注入的對象1、Service最核心3、Controller只做“協(xié)議層”4、請求增強(qiáng)類約束和治理1、Middleware請求最外層2、Guard訪問控制層?3、Pipe參數(shù)治理層?4、Interceptor橫切增強(qiáng)核心?5、Exception Filter異常兜底層?5、IoC / DI 依賴注入NestJS 的靈魂??????????1、認(rèn)識 IoC / DI2、NestJS 中的 IoC / DI①、定義 Provider能力②、消費(fèi) Provider不再 new③、用 Module 把能力“聲明”給容器七、傳統(tǒng) MVC vs NestJS核心差異總覽表重點(diǎn)版??八、標(biāo)準(zhǔn)企業(yè)級 NestJS 分層建議規(guī)范版九、「企業(yè)業(yè)務(wù)」架構(gòu)圖十、NestJS、Fastify 和 Express 全方位對比十一、NestJS 默認(rèn)使用 Express做了什么工作十二、如何將 NestJS 的運(yùn)行時(shí)適配器由 Express 替換為 Fastify??1、為什么 NestJS 可以“隨便換” Express / Fastify2、替換為 Fastify標(biāo)準(zhǔn)做法1、安裝依賴必須2、修改 main.ts3、Fastify 專屬能力可選但常用前言NestJS Node.js 世界里的 Spring 框架。一、NestJS 概念NestJS 是一個(gè)基于 TypeScript 的、強(qiáng)約束、架構(gòu)優(yōu)先的 Node.js 服務(wù)端框架。它的核心目標(biāo)不是“寫得快”而是寫得穩(wěn)可擴(kuò)展可維護(hù)可測試可演進(jìn)NestJS 解決的是 Node.js 的「工程失控」問題傳統(tǒng) Node / Express 痛點(diǎn)NestJS 對應(yīng)解決方案目錄結(jié)構(gòu)隨意Module 強(qiáng)約束依賴注入缺失內(nèi)置 IoC 容器中間件混亂Middleware / Guard / Interceptor / Pipe 分層業(yè)務(wù)代碼和框架代碼混在一起Controller / Service / Provider測試?yán)щy天然可 Mock、可單測大型項(xiàng)目難以協(xié)作清晰邊界 依賴反轉(zhuǎn)NestJS 是把 Java / Spring 的工程思想 引入到了 Node.js 世界。二、一個(gè)請求在 NestJS 中怎么走請求流程??????你會發(fā)現(xiàn)Controller 不重要它只是一個(gè)“轉(zhuǎn)發(fā)器”真正干活的是 Provider三、NestJS 運(yùn)行架構(gòu)圖簡圖四、NestJS 的核心機(jī)制必須記住??????????如果你只記住了這個(gè)那就記住這個(gè)吧。NestJS 的核心機(jī)制包括模塊化架構(gòu)Module → 結(jié)構(gòu)邊界依賴管理依賴注入IoC / DI Container → NestJS 的靈魂管理 Provider 生命周期解耦、復(fù)用、測試友好ProviderService / Repository / Infra 等 → 一切能力的載體承載業(yè)務(wù)邏輯、數(shù)據(jù)訪問、基礎(chǔ)設(shè)施請求攔截體系Interceptor / Guard / Pipe / Filter → 請求增強(qiáng)橫切邏輯企業(yè)級必備生命周期鉤子 異步機(jī)制 → 支撐啟動(dòng)初始化、關(guān)閉清理、異步外部資源五、NestJS 核心成員全量速覽表建議收藏分類類型 / 名稱是否官方重要性作用推薦場景Provider 類Service?約定俗成?????核心業(yè)務(wù)邏輯業(yè)務(wù)處理、狀態(tài)流轉(zhuǎn)、任務(wù)編排Repository?架構(gòu)約定????數(shù)據(jù)訪問抽象DB 操作、ORM 封裝Infra?架構(gòu)約定????外部依賴封裝MQ / Redis / SDK / OSSFactory?????動(dòng)態(tài)創(chuàng)建 Provider 實(shí)例Redis / MQ / 多租戶 DB / SDK 初始化Value????常量 / 配置注入feature flag、常量、枚舉Class?????多實(shí)現(xiàn)替換支付渠道、多通道消息、存儲服務(wù)Async?????異步初始化 Provider異步連接、遠(yuǎn)程配置加載Token?????抽象解耦多實(shí)現(xiàn)注入、接口替換、架構(gòu)解耦Controller 類HTTP Controller??????接收 REST 請求CRUD、業(yè)務(wù)接口WebSocket Gateway????實(shí)時(shí)雙向通信聊天系統(tǒng)、實(shí)時(shí)通知Microservice Controller?????消息通信分布式任務(wù)、事件總線RPC Controller????遠(yuǎn)程調(diào)用內(nèi)部服務(wù) RPCGraphQL Resolver????GraphQL 請求處理查詢/變更/訂閱請求增強(qiáng)類Middleware????請求預(yù)處理日志、requestId、簡單 authGuard?????權(quán)限控制登錄校驗(yàn)、RBAC、數(shù)據(jù)權(quán)限Pipe?????參數(shù)校驗(yàn) / 轉(zhuǎn)換DTO 校驗(yàn)、類型轉(zhuǎn)換、臟數(shù)據(jù)防護(hù)Interceptor??????橫切增強(qiáng)日志、性能監(jiān)控、統(tǒng)一響應(yīng)、緩存、事務(wù)Exception Filter?????異常捕獲全局異常處理、日志、監(jiān)控上報(bào)模塊與應(yīng)用Module??????架構(gòu)邊界、依賴管理拆分業(yè)務(wù)模塊、管理 ProviderApp / Application??????系統(tǒng)啟動(dòng)與關(guān)閉啟動(dòng)模塊、全局 Provider 管理核心系統(tǒng)級成員IoC Container??????Provider 依賴管理Singleton / Request / Transient 管理Reflect Metadata?????裝飾器元數(shù)據(jù)路由、驗(yàn)證、權(quán)限、AOPPlatform Adapter????平臺適配Express / Fastify / Microservice重點(diǎn)關(guān)注 5 顆 ? 和 4 顆 ? 的。下面我們分別研究下這里面的重要成員。六、重點(diǎn)核心成員「逐個(gè)突破」1、Module結(jié)構(gòu)與邊界??????????為什么需要 Module系統(tǒng)會越來越大不分模塊 一團(tuán)亂麻作用聲明「這個(gè)模塊有哪些能力」支持分層架構(gòu)Controller → Service → Repository → Infra控制依賴可見性支持模塊復(fù)用、懶加載定義業(yè)務(wù)邊界保證系統(tǒng)清晰邊界和高可維護(hù)性特性imports引入其他模塊providers聲明模塊內(nèi)部 Providercontrollers聲明 Controllerexports輸出可被其他模塊使用的 Provider示例Module({imports:[],controllers:[],providers:[],exports:[]})exportclassUserModule{}2、Provider一切可注入的對象定義凡是能被 Nest IoC 注入的對象都是 Provider。重要性一切業(yè)務(wù) 和 基礎(chǔ)設(shè)施 都寫在 Provider 中。作用承載業(yè)務(wù)邏輯數(shù)據(jù)訪問基礎(chǔ)設(shè)施封裝原則單一職責(zé)精簡 Controller → Provider 專注業(yè)務(wù)可替換、多實(shí)現(xiàn)Token / Class ProviderProvider 生命周期三種作用域Scope生命周期特點(diǎn)Singleton應(yīng)用啟動(dòng)實(shí)例化 → 全局共享 → 應(yīng)用關(guān)閉銷毀Request每次請求生成實(shí)例 → 請求結(jié)束銷毀Transient每次注入生成實(shí)例 → 使用完銷毀Provider 主要包括以下成員ServiceRepositoryCache / MQSDK 封裝工具類企業(yè)級應(yīng)用Service 調(diào)用 Repository Infra → 保證 Controller 薄Factory / Async Provider → 異步初始化外部資源Token / Class Provider → 支持支付渠道、消息通道替換1、Service最核心NestJS 的 Service是 IoC 容器中的“業(yè)務(wù)能力單元”它負(fù)責(zé)表達(dá)業(yè)務(wù)規(guī)則、編排業(yè)務(wù)流程業(yè)務(wù)正確性而不是處理技術(shù)細(xì)節(jié)。Service 的本質(zhì)非常重要維度本質(zhì)架構(gòu)層面Application / Domain 層的載體IoC 角度被容器托管的可注入對象職責(zé)角度業(yè)務(wù)規(guī)則 業(yè)務(wù)流程編排可測試性可 Mock、可獨(dú)立測試的純邏輯單元? Service 應(yīng)該做的事類型舉例業(yè)務(wù)規(guī)則狀態(tài)流轉(zhuǎn)、校驗(yàn)業(yè)務(wù)流程下單 → 鎖庫存 → 支付 → 發(fā)通知事務(wù)控制DB 事務(wù) / 分布式事務(wù)資源協(xié)調(diào)DB Redis MQ業(yè)務(wù)抽象統(tǒng)一業(yè)務(wù)接口? Service 不應(yīng)該做的事禁止原因解析 HTTP 請求屬于 Controller操作 Request / Response破壞分層寫 SQLRepository 的職責(zé)寫 Redis Key 細(xì)節(jié)Infra 關(guān)注點(diǎn)關(guān)心 UI 展示Presentation 關(guān)注點(diǎn)示例Injectable()exportclassUserService{}3、Controller只做“協(xié)議層”Controller 是 NestJS 的“傳輸適配層Transport Adapter”而不是業(yè)務(wù)層。Controller 的職責(zé)必須克制接收請求參數(shù)提取返回響應(yīng)? 不寫業(yè)務(wù)邏輯Controller 的本質(zhì)非常重要維度本質(zhì)架構(gòu)層Presentation Layer表現(xiàn)層職責(zé)協(xié)議適配 請求入口復(fù)雜度應(yīng)該極低生命周期被 IoC 管理可替換性可以被 GraphQL / RPC / MQ 替代Controller 不是核心邏輯所在而是“可被替換的一層殼”。與 MVC 架構(gòu)的 Controller 過于肥大不同NestJS 刻意對 Controller 做了瘦身業(yè)務(wù)邏輯全部下沉到 ServiceController 只負(fù)責(zé)“接、轉(zhuǎn)、發(fā)調(diào)”。Controller 越薄系統(tǒng)越健康。? Controller 能干什么明確邊界職責(zé)說明路由聲明Controller / Get協(xié)議綁定HTTP / GraphQL / RPC參數(shù)獲取Body / Query / ParamDTO 校驗(yàn)Pipe class-validator調(diào)用 Service只調(diào)用、不實(shí)現(xiàn)返回結(jié)果統(tǒng)一響應(yīng)結(jié)構(gòu)? Controller 禁止做的事紅線禁止項(xiàng)為什么寫業(yè)務(wù)規(guī)則破壞分層操作數(shù)據(jù)庫嚴(yán)重越權(quán)寫 Redis / MQInfra 泄漏try/catch 業(yè)務(wù)異常應(yīng)交給 Filter拼裝復(fù)雜對象應(yīng)在 ServiceController 的典型結(jié)構(gòu)標(biāo)準(zhǔn)范式Controller(orders)exportclassOrderController{constructor(privatereadonlyorderService:OrderService,){}Post()create(Body()dto:CreateOrderDto){returnthis.orderService.create(dto);}}Controller 的分類企業(yè)級常見REST Controller最常見RPC / 微服務(wù) ControllerGraphQL ResolverController 的另一種形態(tài)BFF Controller前端友好好 Controller 的 5 條鐵律設(shè)計(jì)原則每個(gè)方法 ≤ 5 行只做參數(shù)映射不寫 if / for只依賴 Service / Facade返回 DTO / ViewModel4、請求增強(qiáng)類約束和治理定義請求增強(qiáng)類 不處理業(yè)務(wù)本身而是對“請求/響應(yīng)生命周期”進(jìn)行增強(qiáng)、約束、治理的組件。它們的共同特點(diǎn)是關(guān)心 請求什么時(shí)候來、是否允許進(jìn)入、如何變形、如何返回、如何兜底是 AOP面向切面編程思想的具體落地? 不關(guān)心具體業(yè)務(wù)作用在請求進(jìn)入 Controller 前、響應(yīng)返回前進(jìn)行增強(qiáng)保證 Controller 只處理請求入口業(yè)務(wù)邏輯在 ProviderNestJS 的五大請求增強(qiáng)類官方類型執(zhí)行位置核心職責(zé)Middleware最外層原始請求預(yù)處理GuardController 之前是否允許進(jìn)入Pipe參數(shù)進(jìn)入 Controller 之前校驗(yàn) / 轉(zhuǎn)換InterceptorController 前后橫切增強(qiáng)Exception Filter異常拋出后統(tǒng)一異常處理1、Middleware請求最外層定位對原始 Request / Response 做最早處理特點(diǎn)基于 Express / Fastify無法使用 DI或能力有限更偏“框架級”典型用途requestId 注入原始日志CORS簡單鑒權(quán)不推薦復(fù)雜? 不適合復(fù)雜權(quán)限業(yè)務(wù)邏輯依賴 Service 的場景2、Guard訪問控制層?定位決定“這個(gè)請求有沒有資格進(jìn)入 Controller”特點(diǎn)返回 boolean / Promise可以使用 DI強(qiáng)語義是否放行典型用途登錄校驗(yàn)RBAC / ABAC 權(quán)限數(shù)據(jù)級權(quán)限是否能訪問某資源canActivate(context:ExecutionContext):boolean{constreqcontext.switchToHttp().getRequest()return!!req.user}Guard 是權(quán)限體系的唯一正解3、Pipe參數(shù)治理層?定位參數(shù)進(jìn)入 Controller 前的“質(zhì)量控制器”特點(diǎn)在參數(shù)級別執(zhí)行可轉(zhuǎn)換 / 可拋錯(cuò)強(qiáng)配合 DTO class-validator典型用途參數(shù)校驗(yàn)類型轉(zhuǎn)換默認(rèn)值填充防臟數(shù)據(jù)Body(newValidationPipe())create(Body()dto:CreateUserDto){}Pipe 參數(shù)防火墻4、Interceptor橫切增強(qiáng)核心?定位Controller 前后包裹執(zhí)行特點(diǎn)可拿到返回值可修改響應(yīng)可做 AOP典型用途非常關(guān)鍵統(tǒng)一響應(yīng)格式日志 性能統(tǒng)計(jì)緩存事務(wù)控制冪等控制returnnext.handle().pipe(tap(()console.log(after)),)Interceptor 是 NestJS 的靈魂5、Exception Filter異常兜底層?定位異常統(tǒng)一收口特點(diǎn)捕獲 throw 出來的異??煞诸愄幚砜缮蠄?bào)監(jiān)控典型用途HTTP 異常統(tǒng)一格式錯(cuò)誤碼規(guī)范Sentry / 日志系統(tǒng)Catch(HttpException)exportclassHttpFilter{}Filter 系統(tǒng)穩(wěn)定器5、IoC / DI 依賴注入NestJS 的靈魂??????????1、認(rèn)識 IoC / DIIoC控制反轉(zhuǎn)是一種新的設(shè)計(jì)思想——提供了另一種創(chuàng)建對象的方式不用 new。DI依賴注入是 IoC 最主流、最工程化的實(shí)現(xiàn)方式DI 容器在運(yùn)行時(shí)把對象所需的依賴“注入”進(jìn)去。IoC 的核心反轉(zhuǎn)點(diǎn)維度傳統(tǒng)方式IoC創(chuàng)建對象自己 new容器創(chuàng)建管理依賴對象自己容器統(tǒng)一管理生命周期不可控可配置替換實(shí)現(xiàn)困難極其容易從“對象控制一切” → “容器控制一切”常見 DI 方式方式示例構(gòu)造函數(shù)注入NestJS / Spring屬性注入Angular方法注入少見NestJS 使用的是 構(gòu)造函數(shù)注入最安全。2、NestJS 中的 IoC / DI不理解 IoC / DI就永遠(yuǎn)只是在“用 NestJS 寫接口”而不是“用 NestJS 構(gòu)建系統(tǒng)”。NestJS 的核心能力本質(zhì)上是一個(gè)“強(qiáng)約束、強(qiáng)治理的 IoC 容器”。IoC 是“控制權(quán)反轉(zhuǎn)”DI 是“反轉(zhuǎn)的具體實(shí)現(xiàn)方式”。作用管理 Provider 生命周期Singleton / Request / Transient支撐模塊間解耦、可替換實(shí)現(xiàn)、可 Mock 測試核心價(jià)值解耦 → Controller / Service / Repository 不直接創(chuàng)建依賴復(fù)用 → 同一 Provider 可被多個(gè)模塊注入測試友好 → Mock / 替換 Provider 容易「沒有 IoC」會發(fā)生什么對照組classPaymentService{pay(){returnpay success}}classOrderService{privatepaymentServicenewPaymentService()createOrder(){returnthis.paymentService.pay()}}? 問題OrderService 強(qiáng)依賴 PaymentService無法替換實(shí)現(xiàn)難測試、難擴(kuò)展使用 NestJS IoC 的最小示例推薦記?、?、定義 Provider能力Injectable()exportclassPaymentService{pay(){returnpay success}}②、消費(fèi) Provider不再 newInjectable()exportclassOrderService{constructor(privatereadonlypaymentService:PaymentService,){}createOrder(){returnthis.paymentService.pay()}}OrderService 不關(guān)心 PaymentService 怎么來的③、用 Module 把能力“聲明”給容器Module({providers:[PaymentService,OrderService],})exportclassOrderModule{}到這里為止OrderService 的依賴關(guān)系已經(jīng)“聲明完畢”實(shí)例創(chuàng)建權(quán)完全交給 Nest根據(jù)上述“①、②、③”整個(gè)典例來看當(dāng) Nest 啟動(dòng)時(shí)發(fā)生了什么IoC 真正生效的地方掃描 OrderModul發(fā)現(xiàn) PaymentService、OrderService解析 OrderService 構(gòu)造函數(shù)參數(shù)自動(dòng)創(chuàng)建 PaymentService注入進(jìn) OrderService??OrderService 從來沒 new 過任何東西。七、傳統(tǒng) MVC vs NestJS核心差異總覽表重點(diǎn)版??維度傳統(tǒng) MVCNestJS架構(gòu)中心ControllerModule Provider設(shè)計(jì)核心請求 → 響應(yīng)能力組合 依賴注入依賴管理手動(dòng) new / 引入IoC 容器統(tǒng)一管理業(yè)務(wù)組織Controller 膨脹Service 解耦、可組合擴(kuò)展機(jī)制Hook / 中間件有限Guard / Pipe / Interceptor / Filter面向?qū)ο笃^程式強(qiáng) OOP DDD 友好測試友好度較弱極強(qiáng)天然 Mock企業(yè)級能力中小項(xiàng)目為主天然支持大型系統(tǒng)八、標(biāo)準(zhǔn)企業(yè)級 NestJS 分層建議規(guī)范版src/├── modules/│ └── business/│ ├── business.controller.ts │ ├── business.service.ts ← 業(yè)務(wù) │ ├── business.repository.ts ← 數(shù)據(jù) │ ├── clients/│ │ └── aliyun.client.ts ← Infra │ ├── dto/│ └── business.module.ts ├── infra/│ ├── redis/│ ├── logger/│ └── queue/九、「企業(yè)業(yè)務(wù)」架構(gòu)圖十、NestJS、Fastify 和 Express 全方位對比維度ExpressFastifyNestJS定位輕量級 HTTP 框架高性能 HTTP 框架企業(yè)級應(yīng)用框架抽象層級低接近原生 HTTP中HTTP Schema高平臺級是否是應(yīng)用框架???默認(rèn) HTTP 內(nèi)核自身自身Express可換 Fastify是否可替換 HTTP 內(nèi)核???核心設(shè)計(jì)思想Middleware 鏈Plugin SchemaModule Provider IoC架構(gòu)中心app / routerserver / pluginModule / Provider依賴注入DI???核心能力IoC 容器???模塊化能力???AOP / 攔截體系???Guard / Pipe / Interceptor / Filter請求生命周期治理手寫部分完整、標(biāo)準(zhǔn)化Controller 概念???Service 層約定約定一等公民DTO / 參數(shù)校驗(yàn)手寫Schema 原生支持Pipe class-validator權(quán)限體系手寫手寫Guard官方模式異常處理Error MiddlewareError HandlerException Filter統(tǒng)一響應(yīng)手寫手寫Interceptor事務(wù) / 冪等 / 緩存手寫手寫Interceptor / Provider中間件機(jī)制MiddlewarePlugin更強(qiáng)Middleware最外層插件生態(tài)?????????????基于 Adapter類型支持TS???????????性能????????????取決于底層高并發(fā)能力一般非常強(qiáng)強(qiáng)Fastify 模式測試友好度一般一般極強(qiáng)天然 Mock微服務(wù)支持???官方GraphQL 支持???WebSocket 支持手動(dòng)插件官方支持學(xué)習(xí)成本低中高代碼規(guī)范約束極低低高強(qiáng)約束項(xiàng)目規(guī)模適配小中中 → 超大典型項(xiàng)目簡單 API / Demo高性能 API企業(yè)后臺 / 中臺 / BFF架構(gòu)演進(jìn)成本高中低可維護(hù)性易失控中等非常強(qiáng)是否適合大型團(tuán)隊(duì)????十一、NestJS 默認(rèn)使用 Express做了什么工作在 NestJS 中Express 只是“HTTP 運(yùn)行時(shí)適配器Runtime Adapter”。其他所有“應(yīng)用級能力”幾乎全部由 NestJS 自己接管。NestJS應(yīng)用框架 ↓ ExpressHTTP適配器/執(zhí)行器 ↓ Node.js運(yùn)行時(shí)Express 不再是“框架”而是“運(yùn)行時(shí)引擎”層級負(fù)責(zé)者HTTP 協(xié)議Express路由注冊NestJS請求生命周期NestJS權(quán)限 / 校驗(yàn)NestJS業(yè)務(wù)邏輯NestJS異常治理NestJS響應(yīng)格式NestJS90% 的“應(yīng)用邏輯”已經(jīng)不在 Express 里了十二、如何將 NestJS 的運(yùn)行時(shí)適配器由 Express 替換為 Fastify??既然 Fastify 比 Express 性能更強(qiáng)大那么如何快速將 NestJS 的運(yùn)行時(shí)適配器由 Express 替換為 Fastify 呢NestJS 默認(rèn)使用 Express 時(shí)通過 Platform Adapter 抽象了 Web 層這就給了你替換的機(jī)會你只需要在 bootstrap 階段替換 Adapter就可以無痛切換到 Fastify。1、為什么 NestJS 可以“隨便換” Express / FastifyNestJS 的核心不直接依賴 Express而是依賴 nestjs/platform-* 適配層Nest Core ↓ Platform AdapterExpress/Fastify ↓HTTPServer這正是 NestJS IoC 適配器模式 的體現(xiàn)。2、替換為 Fastify標(biāo)準(zhǔn)做法1、安裝依賴必須npm installnestjs/platform-fastify fastify?? 不需要再裝 express2、修改 main.tsimport{NestFactory}fromnestjs/coreimport{AppModule}from./app.moduleimport{FastifyAdapter,NestFastifyApplication,}fromnestjs/platform-fastifyasyncfunctionbootstrap(){constappawaitNestFactory.createNestFastifyApplication(AppModule,newFastifyAdapter(),)awaitapp.listen(3000,0.0.0.0)}bootstrap()? 到這里Express 已被徹底替換為 Fastify3、Fastify 專屬能力可選但常用注冊 Fastify 插件constappawaitNestFactory.create(AppModule,newFastifyAdapter(),)app.register(require(fastify/cors))注意Fastify 插件 ≠ Nest Middleware使用 Fastify Request / Replyimport{FastifyRequest,FastifyReply}fromfastifyGet()get(Req()req:FastifyRequest,Res()reply:FastifyReply){reply.send({ok:true})}一旦使用 Res()Nest 的響應(yīng)攔截器將失效和 Express 一樣