## 請求生命周期
`Nest`應用程序處理請求并生成回應的過程被稱為**請求生命周期**。使用中間件、管道、守衛和攔截器時,要在請求生命周期中追蹤特定的代碼片段的執行很困難,尤其是在全局、控制器或者路由的部件中。一般來說,一個請求流經中間件、守衛與攔截器,然后到達管道,并最終回到攔截器中的返回路徑中(從而產生響應)。
### 中間件
中間件以特殊的順序執行。首先,`Nest`運行全局綁定的中間件(例如`app.use`中綁定的中間件),然后運行在路徑中指定的**模塊綁定的中間件**。中間件以他們綁定的次序順序執行,這和在`Express`中的中間件工作原理是類似的。
### 守衛
守衛的執行首先從全局守衛開始,然后處理控制器守衛,最后是路徑守衛。和中間件一樣,守衛的執行也和他們的綁定順序一致。例如:
```typescript
@UseGuards(Guard1, Guard2)
@Controller('cats')
export class CatsController {
constructor(private catsService: CatsService) {}
@UseGuards(Guard3)
@Get()
getCats(): Cats[] {
return this.catsService.getCats();
}
}
```
`Guard1`會在`Guard2`之前執行并且這兩者都先于`Guard3`執行。
?> 在提到全局綁定和本地綁定時主要是指守衛(或其他部件)綁定的位置不同。如果你正在使用`app.useGlobalGuard()`或者通過模塊提供一個部件,它就是全局綁定的。否則,當一個裝飾器在控制器類之前時,它就是綁定在控制器上的,當裝飾器在路徑聲明之前時它就是綁定在路徑上的。
### 攔截器
攔截器在大部分情況下和守衛類似。只有一種情況例外:當攔截器返回的是一個`RxJS Observables`時,`observables`是以先進后出的順序執行的。因此,入站請求是按照標準的全局、控制器和路由層次執行的,但請求的響應側(例如,當從一個控制器方法的處理器返回時)則是從路由到控制器再到全局。另外,由管道、控制器或者服務拋出的任何錯誤都可以在攔截器的`catchError`操作者中被讀取。
### 管道
管道按照標準的從全局到控制器再到路由的綁定順序,遵循先進先出的原則按照`@usePipes()`參數次序順序執行。然而,在路由參數層次,如果由多個管道在執行,則會按照自后向前的參數順序執行,這在路由層面和控制器層面的管道中同樣如此,例如,我們有如下控制器:
```typescript
@UsePipes(GeneralValidationPipe)
@Controller('cats')
export class CatsController {
constructor(private catsService: CatsService) {}
@UsePipes(RouteSpecificPipe)
@Patch(':id')
updateCat(
@Body() body: UpdateCatDTO,
@Param() params: UpdateCatParams,
@Query() query: UpdateCatQuery,
) {
return this.catsService.updateCat(body, params, query);
}
}
```
在這里`GeneralValidationPipe`會先執行`query`,然后是`params`,最后是`body`對象,接下來在執行`RouteSpecificPipe`管道時同樣按照上述次序執行。如果存在任何參數層的管道,它會在(同樣的,按照自后向前的參數順序)控制器和路由層的管道之后執行。
### 過濾器
過濾器是唯一一個不按照全局第一順序執行的組件。而是會從最低層次開始處理,也就是說先從任何路由綁定的過濾器開始,然后是控制器層,最后才是全局過濾器。注意,異常無法從過濾器傳遞到另一個過濾器;如果一個路由層過濾器捕捉到一個異常,一個控制器或者全局層面的過濾器就捕捉不到這個異常。如果要實現類似的效果可以在過濾器之間使用繼承。
> 過濾器僅在請求過程中任何沒有捕獲的異常發生時執行。捕獲的異常如`try/catch`語句不會觸發過濾器。一旦遇到未處理的異常,請求接下來的生命周期會被忽略并直接跳轉到過濾器。
### 總結
一般來說,請求生命周期大致如下:
1. 收到請求
2. 全局綁定的中間件
3. 模塊綁定的中間件
4. 全局守衛
5. 控制層守衛
6. 路由守衛
7. 全局攔截器(控制器之前)
8. 控制器層攔截器 (控制器之前)
9. 路由攔截器 (控制器之前)
10. 全局管道
11. 控制器管道
12. 路由管道
13. 路由參數管道
14. 控制器(方法處理器)
15. 服務(如果有)
16. 路由攔截器(請求之后)
17. 控制器攔截器 (請求之后)
18. 全局攔截器 (請求之后)
19. 異常過濾器 (路由,之后是控制器,之后是全局)
20. 服務器響應
- 介紹
- 概述
- 第一步
- 控制器
- 提供者
- 模塊
- 中間件
- 異常過濾器
- 管道
- 守衛
- 攔截器
- 自定義裝飾器
- 基礎知識
- 自定義提供者
- 異步提供者
- 動態模塊
- 注入作用域
- 循環依賴
- 模塊參考
- 懶加載模塊
- 應用上下文
- 生命周期事件
- 跨平臺
- 測試
- 技術
- 數據庫
- Mongo
- 配置
- 驗證
- 緩存
- 序列化
- 版本控制
- 定時任務
- 隊列
- 日志
- Cookies
- 事件
- 壓縮
- 文件上傳
- 流式處理文件
- HTTP模塊
- Session(會話)
- MVC
- 性能(Fastify)
- 服務器端事件發送
- 安全
- 認證(Authentication)
- 授權(Authorization)
- 加密和散列
- Helmet
- CORS(跨域請求)
- CSRF保護
- 限速
- GraphQL
- 快速開始
- 解析器(resolvers)
- 變更(Mutations)
- 訂閱(Subscriptions)
- 標量(Scalars)
- 指令(directives)
- 接口(Interfaces)
- 聯合類型
- 枚舉(Enums)
- 字段中間件
- 映射類型
- 插件
- 復雜性
- 擴展
- CLI插件
- 生成SDL
- 其他功能
- 聯合服務
- 遷移指南
- Websocket
- 網關
- 異常過濾器
- 管道
- 守衛
- 攔截器
- 適配器
- 微服務
- 概述
- Redis
- MQTT
- NATS
- RabbitMQ
- Kafka
- gRPC
- 自定義傳輸器
- 異常過濾器
- 管道
- 守衛
- 攔截器
- 獨立應用
- Cli
- 概述
- 工作空間
- 庫
- 用法
- 腳本
- Openapi
- 介紹
- 類型和參數
- 操作
- 安全
- 映射類型
- 裝飾器
- CLI插件
- 其他特性
- 遷移指南
- 秘籍
- CRUD 生成器
- 熱重載
- MikroORM
- TypeORM
- Mongoose
- 序列化
- 路由模塊
- Swagger
- 健康檢查
- CQRS
- 文檔
- Prisma
- 靜態服務
- Nest Commander
- 問答
- Serverless
- HTTP 適配器
- 全局路由前綴
- 混合應用
- HTTPS 和多服務器
- 請求生命周期
- 常見錯誤
- 實例
- 遷移指南
- 發現
- 誰在使用Nest?