<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ### 控制器 控制器負責處理傳入的**請求**并將**響應**返回給客戶端。 ![](https://docs.nestjs.com/assets/Controllers_1.png) 控制器的目的是接收應用程序的特定請求。**路由**機制控制哪個控制器接收哪個請求。很多時候,每個控制器都有多個路由,不同的路由可以執行不同的動作。 為了創建一個基本的控制器,我們使用類和**裝飾器**。裝飾器將類與所需的元數據相關聯,并使 Nest 能夠創建路由映射(將請求綁定到相應的控制器)。 > **提示:** 為了快速創建內置[驗證的 CRUD 控制器,您可以使用 CLI 的](https://docs.nestjs.com/techniques/validation)[CRUD 生成器](https://docs.nestjs.com/recipes/crud-generator#crud-generator):`nest g resource [name]`。 #### 路由[#](#routing) 在下面的示例中,我們將使用`@Controller()`裝飾器,它是定義基本控制器所**必需的。**我們將指定一個可選的路由路徑前綴`cats`。在裝飾器中使用路徑前綴`@Controller()`可以讓我們輕松地對一組相關路由進行分組,并最大限度地減少重復代碼。例如,我們可以選擇將一組用于管理與`/customers`下的客戶實體進行互動的路由進行分組。這樣,我們可以在`@Controller()`裝飾器中指定路徑前綴`customers`,這樣我們就不必為文件中的每個路由重復該部分路徑。 /\* cats.controller.ts \*/ ~~~typescript import { Controller, Get } from '@nestjs/common'; @Controller('cats') export class CatsController { @Get() findAll(): string { return 'This action returns all cats'; } } ~~~ > **提示**:要使用 CLI 創建控制器,只需執行`$ nest g controller cats`命令。 `findAll()` 方法之前的`@Get()`HTTP 請求方法裝飾器告訴 Nest 為 HTTP 請求的特定端點創建處理程序。端點對應于 HTTP 請求方法(本例中為 GET)和路由路徑。什么是路由路徑?處理程序的路由路徑是通過連接為控制器聲明的(可選)前綴和方法的裝飾器中指定的任何路徑來確定的。由于我們已經為每個路由 (`cats`) 聲明了一個前綴,并且沒有在裝飾器中添加任何路徑信息,Nest 會將`GET /cats`請求映射到這個處理程序。如上所述,該路徑包括可選的控制器路徑前綴**和**請求方法裝飾器中聲明的任何路徑字符串。例如,路徑前綴`customers`與裝飾器路徑前綴`@Get('profile')`將組合為`GET /customers/profile`。 在上面的示例中,當對這個端點發出 GET 請求時,Nest 會將請求路由到我們用戶定義的`findAll()`方法。請注意,我們在這里選擇的方法名稱是完全任意的。我們顯然必須聲明一個綁定路由的方法,但是 Nest 對選擇的方法名沒有任何意義。 此方法將返回 200 狀態代碼和相關的響應,在本例中它只是一個字符串。為什么會這樣?為了解釋,我們將首先介紹 Nest 使用兩種**不同**的選項來操作響應的概念: | | | | :----------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 標準(推薦) | 使用這個內置方法,當請求處理程序返回一個 `JavaScript` 對象或數組時,它將自動序列化為 `JSON`。但是,當它返回一個 `JavaScript` 基本類型(例如`string、number、boolean`)時, Nest 將只發送該值而不嘗試對其進行序列化。這使響應處理變得簡單:只需要返回值,其余的由 Nest 負責。此外,響應的狀態碼默認始終為 200,除了使用 201 的 POST 請求。我們可以通過在處理程序級別添加裝飾器來輕松更改此行為(請參閱狀態碼)。 | | 類庫特有的 | 我們可以在函數簽名處通過 `@Res()` 注入類庫特定的響應對象(例如, `Express`)。使用此方法,你就能使用由該響應對象暴露的原生響應處理函數。例如,使用 `Express`,您可以使用 `response.status(200).send()` 構建響應 | > **警告**:Nest 檢測處理程序何時使用`@Res()`or`@Next()`,表明您選擇了特定于庫的選項。如果同時使用這兩種方法,則該單一路線的標準方法會**自動禁用**,并且將不再按預期工作。要同時使用這兩種方法(例如,通過注入響應對象以僅設置 cookie/標頭但仍將其余部分留給框架),你必須在裝飾器`@Res({ passthrough: true })`中將`passthrough`選項設為`true` #### 請求對象[#](#request-object) 處理程序有時需要訪問客戶端的**請求**細節。Nest 提供了對底層平臺(默認為`Express`)的[**請求對象**](http://expressjs.com/en/api.html#req)(`request`)的訪問方式。我們可以在處理函數的簽名中使用`@Req()`裝飾器,指示 Nest 將請求對象注入處理程序。 /\* cats.controller.ts \*/ ~~~typescript import { Controller, Get, Req } from '@nestjs/common'; import { Request } from 'express'; @Controller('cats') export class CatsController { @Get() findAll(@Req() request: Request): string { return 'This action returns all cats'; } } ~~~ > **提示**:為了利用`express`類型(如`request: Request`上面的參數示例),安裝`@types/express`包。 `Request`對象代表`HTTP`請求,并具有請求查詢字符串、參數、HTTP 標頭(HTTP header) 和 正文(HTTP body)的屬性([在此處](https://expressjs.com/en/api.html#req)閱讀更多內容)。在大多數情況下,沒有必要手動獲取這些屬性。我們可以使用開箱即用的專用裝飾器,例如`@Body()`或者`@Query()`。下面是Nest提供的裝飾器列表以及它們所代表的底層平臺特定對象的對照列表。 | | | | ------------------------- | --------------------------------- | | `@Request(),@Req()` | `req` | | `@Response(),@Res()*` | `res` | | `@Next()` | `next` | | `@Session()` | `req.session` | | `@Param(key?: string)` | `req.params`/`req.params[key]` | | `@Body(key?: string)` | `req.body`/`req.body[key]` | | `@Query(key?: string)` | `req.query`/`req.query[key]` | | `@Headers(name?: string)` | `req.headers`/`req.headers[name]` | | `@Ip()` | `req.ip` | | `@HostParam()` | `req.hosts` | 為了與底層 HTTP 平臺(例如 `Express` 和 `Fastify`)的類型兼容,Nest 提供`@Res()`和`@Response()`裝飾器。`@Res()`只是 . 的別名`@Response()`。兩者都直接暴露了底層的原生平臺`response`對象接口。使用它們時,您還應該導入底層庫的類型(例如,`@types/express`)以充分利用它們。請注意,當您注入其中一個`@Res()`或`@Response()`方法處理程序時,您會將 Nest 置于該處理程序**的庫特定模式**,并且您將負責管理響應。`response`這樣做時,您必須通過調用對象(例如,`res.json(...)`或)來發出某種響應`res.send(...)`,否則 HTTP 服務器將掛起。 > **提示**:要了解如何創建自己的自定義裝飾器,請訪問[本章](https://docs.nestjs.com/custom-decorators)。 #### 資源[#](#resources) 之前,我們定義了一個端點來獲取`cats`資源(**GET**路由)。我們通常還希望提供一個創建新記錄的端點。為此,讓我們創建**POST**處理程序: /\* cats.controller.ts \*/ ~~~typescript import { Controller, Get, Post } from '@nestjs/common'; @Controller('cats') export class CatsController { @Post() create(): string { return 'This action adds a new cat'; } @Get() findAll(): string { return 'This action returns all cats'; } } ~~~ 就是這么簡單。Nest 為所有標準 HTTP 方法提供裝飾器:`@Get()`、`@Post()`、`@Put()`、`@Delete()`、`@Patch()`、`@Options()`和`@Head()`.此外,`@All()`定義一個用于處理所有 HTTP 請求方法的處理程序。 #### 路由通配符[#](#route-wildcards) 路由也支持基于模式匹配。例如,星號用作通配符,將匹配任何字符組合。 ~~~typescript @Get('ab*cd') findAll() { return 'This route uses a wildcard'; } ~~~ `'ab*cd'`路由路徑將匹配、`abcd`、`ab_cd`等`abecd`。字符`?`,`+`,`*`, 和`()`可以在路由路徑中使用,并且是它們的正則表達式對應項的子集。連字符 (`-`) 和點 (`.`) 由基于字符串的路徑逐字解析。 #### 狀態碼[#](#status-code) 如上所述,默認情況下響應**狀態代碼**始終為**200**,但 POST 請求(**默認響應狀態碼為201**)除外。`@HttpCode(...)`我們可以通過在處理程序級別添加裝飾器來輕松更改此行為。 ~~~typescript @Post() @HttpCode(204) create() { return 'This action adds a new cat'; } ~~~ > **提示:**`HttpCode`從`@nestjs/common`包中導入。 通常,您的狀態代碼不是靜態的,而是取決于各種因素。在這種情況下,您可以使用類庫特有(library-specific)的**`response`**(使用 注入`@Res()`)對象(或者如果出現錯誤,則拋出異常)。 #### 標頭[#](#headers) 要指定自定義響應標頭,您可以使用`@Header()`裝飾器或特定于庫的響應對象(并`res.header()`直接調用)。 ~~~typescript @Post() @Header('Cache-Control', 'none') create() { return 'This action adds a new cat'; } ~~~ > **提示**:`Header`從`@nestjs/common`包中導入。 #### 重定向[#](#redirection) 要將響應重定向到特定 URL,您可以使用`@Redirect()`裝飾器或類庫特有的響應對象(并`res.redirect()`直接調用)。 `@Redirect()`接受兩個參數,`url`和`statusCode`,兩者都是可選的。如果省略,`statusCode`則默認值為`302(Found)`。 ~~~typescript @Get() @Redirect('https://nestjs.com', 301) ~~~ 有時您可能希望動態確定 HTTP 狀態代碼或重定向 URL。通過從路由處理方法返回一個如下格式的對象來做到這一點: ~~~json { "url": string, "statusCode": number } ~~~ 返回值將覆蓋傳遞給`@Redirect()`裝飾器的所有參數。例如: ~~~typescript @Get('docs') @Redirect('https://docs.nestjs.com', 302) getDocs(@Query('version') version) { if (version && version === '5') { return { url: 'https://docs.nestjs.com/v5/' }; } } ~~~ #### 路由參數[#](#route-parameters) 當您需要接受**動態數據**(dynamic data)作為請求的一部分時(例如,使用`GET /cats/1`來獲取 id 為`1`的`cat`),具有靜態路徑的路由將不起作用。為了定義帶參數的路由,我們可以在路由的路徑中添加路由參數**標記(token)**,以捕獲請求 URL 中該位置的動態值。下面裝飾器示例中的路由參數標記`@Get()`演示了這種用法。以這種方式聲明的路由參數可以使用`@Param()`裝飾器訪問,該裝飾器應添加到函數簽名中。 ~~~typescript @Get(':id') findOne(@Param() params): string { console.log(params.id); return `This action returns a #${params.id} cat`; } ~~~ `@Param()`用于裝飾方法參數(`params`在上面的示例中),并使**路由**參數可用作方法主體內該裝飾方法參數的屬性。如上面的代碼所示,我們可以`id`通過引用來訪問參數`params.id`。您也可以將特定的參數標記傳遞給裝飾器,然后在方法體中直接通過名稱引用路由參數。 > **提示:**`Param`從`@nestjs/common`包中導入。 ~~~typescript @Get(':id') findOne(@Param('id') id: string): string { return `This action returns a #${id} cat`; } ~~~ #### 子域路由[#](#sub-domain-routing) 裝飾器`@Controller`可以接受一個`host`選項,以要求傳入請求的 HTTP 主機匹配某個特定值。 ~~~typescript @Controller({ host: 'admin.example.com' }) export class AdminController { @Get() index(): string { return 'Admin page'; } } ~~~ > **警告:**由于**Fastify**缺乏對嵌套路由器的支持,所以在使用子域路由時,應該使用(默認)`Express` 適配器。 與一個路由路徑`path`類似,該`hosts`選項可以使用標記來捕獲主機名中該位置的動態值。下面裝飾器示例中的主機參數標記`@Controller()`演示了這種用法。以這種方式聲明的主機參數可以使用`@HostParam()`裝飾器訪問,該裝飾器應添加到方法簽名中。 ~~~typescript @Controller({ host: ':account.example.com' }) export class AccountController { @Get() getInfo(@HostParam('account') account: string) { return account; } } ~~~ #### 作用域[#](#scopes) 對于來自不同編程語言背景的人來說,在 Nest 中得知幾乎所有內容都是在傳入請求之間共享的,這可能是出乎意料的。我們有一個到數據庫的連接池、具有全局狀態的單例服務等。請記住,Node.js 不遵循請求/響應多線程無狀態模型,其中每個請求都由單獨的線程處理。因此,使用單例實例對我們的應用程序來說是完全**安全**的。 但是,在某些極端情況下,控制器的基于請求的生命周期可能是期望行為的邊緣情況,例如 GraphQL 應用程序中的每個請求緩存、請求跟蹤或多租戶。[在此處](https://docs.nestjs.com/fundamentals/injection-scopes)了解如何控制作用域。 #### 異步[#](#asynchronicity) 我們喜歡現代 JavaScript,而且我們知道數據提取(data extraction)大多數是**異步**的。這就是為什么 Nest 支持并很好地使用`async`函數的原因。 > **提示:**[在此處](https://kamilmysliwiec.com/typescript-2-1-introduction-async-await)了解有關`async / await`功能的?更多信息[](https://kamilmysliwiec.com/typescript-2-1-introduction-async-await) 每個異步函數都必須返回一個`Promise`.這意味著您可以返回 Nest 能夠自行解析的延遲值。讓我們看一個例子: /* cats.controller.ts */ ```typescript @Get() async findAll(): Promise<any[]> { return []; } ``` 上面的代碼是完全有效的。此外,由于能夠返回 RxJS[可觀察流](http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html),Nest 路由處理程序更加強大。Nest 將自動訂閱下面的源并獲取最后一個發出的值(在流完成)。 ```typescript /* cats.controller.ts */ @Get() findAll(): Observable<any[]> { return of([]); } ``` 上述的兩種方法都是有效的,你可以選擇你喜歡的方式。 #### 請求負載[#](#request-payloads) 我們之前的 POST 路由處理程序示例沒有接受任何客戶端參數,讓我們通過在此處添加`@Body()`裝飾器來解決此問題。 首先(如果您使用 TypeScript),我們需要確定**DTO**(數據傳輸對象)模式。`DTO` 是一個對象,定義數據如何通過網絡發送的。我們可以使用**TypeScript**接口或簡單的類來確定 DTO 模式。有趣的是,我們建議在這里使用**類**。為什么?類是 JavaScript ES6 標準的一部分,因此它們在編譯后的 JavaScript 中被保留為真實實體。另一方面,由于 TypeScript 接口在轉譯過程中被移除,所以Nest 無法在運行時引用它們。這很重要,因為諸如**管道**(Pipe)之類的特性為在運行時訪問變量的元類型提供更多的可能性。 /* create-cat.dto.ts */ ```typescript export class CreateCatDto { readonly name: string; readonly age: number; readonly breed: string; } ``` 它只有三個基本屬性。此后,我們可以在 `CatsController`中使用新創建的 `DTO`: /* cats.controller.ts */ ```typescript @Post() async create(@Body() createCatDto: CreateCatDto) { return 'This action adds a new cat'; } ``` > **提示**:我們在`ValidationPipe`中可以過濾掉不應被方法處理程序接收的屬性。在這種情況下,我們可以將可接受的屬性列入白名單,任何未包含在白名單中的屬性都會自動從結果對象中剝離。在`CreateCatDto`示例中,我們的白名單是`name`、`age`和`breed`屬性。[在這里](https://docs.nestjs.com/techniques/validation#stripping-properties)了解更多。 #### 處理錯誤[#](#handling-errors) [這里](https://docs.nestjs.com/exceptionfilters)有一個單獨的章節介紹處理錯誤(即處理異常)。 #### 完整資源樣本[#](https://docs.nestjs.com/controllers#full-resource-sample) 下面是一個使用幾個可用裝飾器來創建基本控制器的示例。這個控制器公開了幾個方法來訪問和操作內部數據。 ```typescript /* cats.controller.ts */ import { Controller, Get, Query, Post, Body, Put, Param, Delete } from '@nestjs/common'; import { CreateCatDto, UpdateCatDto, ListAllEntities } from './dto'; @Controller('cats') export class CatsController { @Post() create(@Body() createCatDto: CreateCatDto) { return 'This action adds a new cat'; } @Get() findAll(@Query() query: ListAllEntities) { return `This action returns all cats (limit: ${query.limit} items)`; } @Get(':id') findOne(@Param('id') id: string) { return `This action returns a #${id} cat`; } @Put(':id') update(@Param('id') id: string, @Body() updateCatDto: UpdateCatDto) { return `This action updates a #${id} cat`; } @Delete(':id') remove(@Param('id') id: string) { return `This action removes a #${id} cat`; } } ``` > **提示**:Nest CLI 提供了一個生成器(原理圖),它會自動生成**所有樣板代碼**,以幫助我們避免所有這些,并使開發人員的體驗更加簡單。[在此處](https://docs.nestjs.com/recipes/crud-generator)閱讀有關此功能的更多信息。 #### 啟動并運行[#](#getting-up-and-running) 完全定義上述控制器后,Nest 仍然不知道它的`CatsController`存在,因此不會創建此類的實例。 控制器總是屬于一個模塊,這就是我們在裝飾器中包含`controllers`數組的原因。`@Module()`由于我們還沒有定義除 root 之外的任何其他模塊`AppModule`,我們將使用它來介紹`CatsController`: ```typescript /* app.module.ts */ import { Module } from '@nestjs/common'; import { CatsController } from './cats/cats.controller'; @Module({ controllers: [CatsController], }) export class AppModule {} ``` 我們使用裝飾器將元數據附加到模塊類`@Module()`,Nest 現在可以輕松地反映必須安裝哪些控制器。 #### 特定于庫的方法[#](#library-specific-approach) 到目前為止,我們已經討論了 Nest 處理響應的標準方法。操作響應的第二種方法是使用特定于庫的[響應對象](https://expressjs.com/en/api.html#res)。為了注入特定的響應對象,我們需要使用`@Res()`裝飾器。為了顯示差異,讓我們將其重寫`CatsController`為以下內容: ```typescript /* cats.controller.ts */ import { Controller, Get, Post, Res, HttpStatus } from '@nestjs/common'; import { Response } from 'express'; @Controller('cats') export class CatsController { @Post() create(@Res() res: Response) { res.status(HttpStatus.CREATED).send(); } @Get() findAll(@Res() res: Response) { res.status(HttpStatus.OK).json([]); } } ``` 盡管這種方法有效,并且實際上通過提供對響應對象的完全控制(標頭操作、庫特定功能等)在某些方面提供了更大的靈活性,但應謹慎使用。一般來說,這種方法不太清楚,并且確實有一些缺點。主要缺點是您的代碼變得依賴于平臺(因為底層庫可能在響應對象上有不同的 API),并且更難測試(您必須模擬響應對象等)。 此外,在上面的示例中,您失去了與依賴于 Nest 標準響應處理的 Nest 功能的兼容性,例如攔截器和`@HttpCode()`/`@Header()`裝飾器。要解決此問題,您可以將`passthrough`選項設置為`true`,如下所示: ```typescript @Get() findAll(@Res({ passthrough: true }) res: Response) { res.status(HttpStatus.OK); return []; } ``` 現在您可以與本機響應對象進行交互(例如,根據特定條件設置 cookie 或標頭),但將其余部分留給框架。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看