# 自定義路由參數裝飾器
`Nest` 是基于**裝飾器**這種語言特性而創建的。在很多常見的編程語言中,裝飾器是一個廣為人知的概念,但在 `JavaScript` 世界中,這個概念仍然相對較新。為了更好地理解裝飾器是如何工作的,你應該看看 [這篇](https://medium.com/google-developers/exploring-es7-decorators-76ecb65fb841) 文章。下面給出一個簡單的定義:
>`ES2016` 裝飾器是一個表達式,它返回一個可以將目標、名稱和屬性描述符作為參數的函數。通過在裝飾器前面添加一個 `@` 字符并將其放置在你要裝飾的內容的最頂部來應用它。可以為類、方法或屬性定義裝飾器。
## 參數裝飾器
`Nest` 提供了一組非常實用的參數裝飾器,可以結合 `HTTP` 路由處理器(`route handlers`)一起使用。下面的列表展示了`Nest` 裝飾器和原生 `Express`(或 `Fastify`)中相應對象的映射。
| | |
| --------------------------------------------- | ------------------------------------------------ |
| `@Request(),@Req()` | `req` |
| `@Response(),@Res()` | `res` |
| `@Next()` | `next` |
| `@Session()` | `req.session` |
| `@Param(param?: string)` | `req.params / req.params[param]` |
| `@Body(param?: string)` | `req.body / req.body[param]` |
| `@Query(param?: string)` | `req.query / req.query[param]` |
| `@Headers(param?: string)` | `req.headers / req.headers[param]` |
| `@Ip()` | `req.ip` |
| `@HostParam()` | `req.hosts` |
另外,你還可以創建**自定義裝飾器**。這非常有用。
在 `Node.js` 中,會經常將需要傳遞的值加到請求對象的屬性中。然后在每個路由處理程序中手動提取它們,使用如下代碼:
```typescript
const user = req.user;
```
為了使代碼更具可讀性和透明性,我們可以創建一個 `@User()` 裝飾器并在所有控制器中使用它。
> user.decorator.ts
```typescript
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
export const User = createParamDecorator((data: unknown, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
return request.user;
});
```
現在你可以在任何你想要的地方很方便地使用它。
```typescript
@Get()
async findOne(@User() user: UserEntity) {
console.log(user);
}
```
## 傳遞數據
當裝飾器的行為取決于某些條件時,可以使用 `data` 參數將參數傳遞給裝飾器的工廠函數。 一個用例是自定義裝飾器,它通過鍵從請求對象中提取屬性。 例如,假設我們的身份驗證層驗證請求并將用戶實體附加到請求對象。 經過身份驗證的請求的用戶實體可能類似于:
```json
{
"id": 101,
"firstName": "Alan",
"lastName": "Turing",
"email": "alan@email.com",
"roles": ["admin"]
}
```
讓我們定義一個將屬性名作為鍵的裝飾器,如果存在則返回關聯的值(如果不存在或者尚未創建 `user` 對象,則返回 undefined)。
> user.decorator.ts
```typescript
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
export const User = createParamDecorator((data: string, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
const user = request.user;
return data ? user && user[data] : user;
});
```
然后,您可以通過控制器中的 `@User()` 裝飾器訪問以下特定屬性:
```typescript
@Get()
async findOne(@User('firstName') firstName: string) {
console.log(`Hello ${firstName}`);
}
```
您可以使用具有不同鍵的相同裝飾器來訪問不同的屬性。如果用戶對象復雜,使用此方法可以使請求處理程序編寫更容易、并且可讀性更高。
> 對于 `TypeScript` 用戶,請注意這 `createParamDecorator<T>()` 是通用的。這意味著您可以顯式實施類型安全性,例如 `createParamDecorator<string>((data, ctx) => ...)`或者,在工廠函數中指定參數類型,例如`createParamDecorator((data: string, ctx) => ...)` 。如果省略這兩個, 參數 `data` 的類型為 `any`。
## 使用管道
`Nest` 對待自定義的路由參數裝飾器和自身內置的裝飾器(`@Body()`,`@Param()` 和 `@Query()`)一樣。這意味著管道也會因為自定義注釋參數(在本例中為 `user` 參數)而被執行。此外,你還可以直接將管道應用到自定義裝飾器上:
```typescript
@Get()
async findOne(@User(new ValidationPipe()) user: UserEntity) {
console.log(user);
}
```
> 請注意,`validateCustomDecorators` 選項必須設置為 `true`。默認情況下,`ValidationPipe` 不驗證使用自定義裝飾器注釋的參數。
## 裝飾器聚合
`Nest` 提供了一種輔助方法來聚合多個裝飾器。例如,假設您要將與身份驗證相關的所有裝飾器聚合到一個裝飾器中。這可以通過以下方法實現:
```typescript
import { applyDecorators } from '@nestjs/common';
export function Auth(...roles: Role[]) {
return applyDecorators(
SetMetadata('roles', roles),
UseGuards(AuthGuard, RolesGuard),
ApiBearerAuth(),
ApiUnauthorizedResponse({ description: 'Unauthorized"' })
);
}
```
然后,你可以參照以下方式使用 `@Auth()` 自定義裝飾器:
```typescript
@Get('users')
@Auth('admin')
findAllUsers() {}
```
這具有通過一個聲明應用所有四個裝飾器的效果。
> 來自 `@nestjs/swagger` 依賴中的 `@ApiHideProperty()` 裝飾器無法聚合,因此此裝飾器無法正常使用 `applyDecorators` 方法。
- 介紹
- 概述
- 第一步
- 控制器
- 提供者
- 模塊
- 中間件
- 異常過濾器
- 管道
- 守衛
- 攔截器
- 自定義裝飾器
- 基礎知識
- 自定義提供者
- 異步提供者
- 動態模塊
- 注入作用域
- 循環依賴
- 模塊參考
- 懶加載模塊
- 應用上下文
- 生命周期事件
- 跨平臺
- 測試
- 技術
- 數據庫
- 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?