Nest.js系列学习控制器使用示例详解
water 人气:0控制器是什么
控制器负责处理传入的请求和向客户端返回响应,控制器的目的是接收应用的特定请求。路由机制控制哪个控制器接收哪些请求。通常,每个控制器有多个路由,不同的路由可以执行不同的操作。如果要创建一个简单的路由器,我们使用类和装饰器。装饰器将类与所需的元数据相关联,并使nest能够创建路由映射(将请求绑定到相应的控制器)
路由
路由是通过@Coutroller装饰器装饰的一个类,就是一个基本的控制器。@Coutroller接受一个参数,可以轻松的对一组相关的路由进行分组,并最大程度的减少重复代码。
import { Controller, Get } from '@nestjs/common' @Controller('water') export class WaterController { @Get() findAll(): string { return 'water' } }
以上代码findAll方法上有一个@Get装饰器,这个装饰器是http请求方法装饰器,表示创建了一个get请求。而且@Get也可以接受一个参数,表示一个具体的路由路径
import { Controller, Get } from '@nestjs/common' @Controller('water') export class WaterController { @Get('list') findAll(): string { return 'water' } }
然后请求路由的地址是 GET /water/list
Request请求对象
Nest提供对底层平台(默认为Express)的请求对象(request)的访问方式,就可以在处理函数的签名中使用@Req()装饰器。
import { Controller, Get, Req } from '@nestjs/common'; import { Request } from 'express'; @Controller('water') export class CatsController { @Get() findAll(@Req() request: Request): string { return 'water'; } }
Request对象代表HTTP请求体,并具有查询字符串,请求参数,http标头和正文(http body)的属性。下面是装饰器对照的列表
@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 |
多种请求方式
import { Controller, Get, Post } from '@nestjs/common'; @Controller('water') export class CatsController { @Post() create(): string { return 'water'; } @Get() findAll(): string { return 'water'; } }
Nest 为所有标准的 HTTP 方法提供了相应的装饰器:@Put()、@Delete()、@Patch()、@Options()、以及 @Head()。此外,@All() 则用于定义一个用于处理所有 HTTP 请求方法的处理程序。
路由通配符
路由支持模式匹配
@Get('ab*cd') findAll() { return 'water' }
路由路径 'ab*cd' 将匹配 abcd 、ab_cd 、abecd 等。字符 ? 、+ 、 * 以及 () 是它们的正则表达式对应项的子集。连字符(-) 和点(.)按字符串路径逐字解析。
状态码
默认情况下,响应的状态码总是默认为 200,除了 POST 请求(默认响应状态码为 201),我们可以通过在处理函数外添加 @HttpCode(...) 装饰器来轻松更改此行为。
@Post() @HttpCode(204) create() { return 'water'; }
Headers
要指定自定义响应头,可以使用 @header() 装饰器或类库特有的响应对象,(并直接调用 res.header())。
@Post() @Header('Cache-Control', 'none') create() { return 'water'; }
重定向
要将响应重定向到特定的 URL,可以使用 @Redirect() 装饰器或特定于库的响应对象(并直接调用 res.redirect())。
@Redirect() 装饰器有两个可选参数,url 和 statusCode。 如果省略,则 statusCode 默认为 302。
@Get() @Redirect('https://nestjs.com', 301)
有时可能想动态地决定 HTTP 状态代码或重定向 URL。通过从路由处理方法返回一个如下格式的对象
{ "url": string, "statusCode": number }
返回的值将覆盖传递给 @Redirect()装饰器的所有参数。
@Get('docs') @Redirect('https://docs.nestjs.com', 302) getDocs(@Query('version') version) { if (version && version === '5') { return { url: 'https://docs.nestjs.com/v5/' }; } }
路由参数
当您需要接受动态数据(dynamic data)作为请求的一部分时(例如,使用GET /cats/1 来获取 id 为 1 的 cat),带有静态路径的路由将无法工作。为了定义带参数的路由,我们可以在路由路径中添加路由参数标记(token)以捕获请求 URL 中该位置的动态值。下面的 @Get() 装饰器示例中的路由参数标记(route parameter token)演示了此用法。以这种方式声明的路由参数可以使用 @Param() 装饰器访问,该装饰器应添加到函数签名中。
@Get(':id') findOne(@Param() params): string { console.log(params.id); return params.id; }
@Param() 用于修饰一个方法的参数(上面示例中的 params),并在该方法内将路由参数作为被修饰的方法参数的属性。如上面的代码所示,我们可以通过引用 params.id来访问(路由路径中的) id 参数。 您还可以将特定的参数标记传递给装饰器,然后在方法主体中按参数名称直接引用路由参数。
@Get(':id') findOne(@Param('id') id): string { return id; }
子域路由
@Controller 装饰器可以接受一个 host 选项,以要求传入请求的 HTTP 主机匹配某个特定值。
@Controller({ host: 'admin.example.com' }) export class AdminController { @Get() index(): string { return 'Admin page'; } }
与一个路由路径 path 类似,该 hosts 选项可以使用参数标识(token)来捕获主机名中该位置的动态值。下面的 @Controller() 装饰器示例中的主机参数标识(host parameter token)演示了此用法。可以使用 @HostParam() 装饰器访问以这种方式声明的主机参数,该装饰器应添加到方法签名中。
@Controller({ host: ':account.example.com' }) export class AccountController { @Get() getInfo(@HostParam('account') account: string) { return account; }
异步性
Nest支持异步函数特性,每个异步函数都必须返回一个Promise
@Get() async findAll(): Promise<any[]> { return []; }
也可以使用RxJs observable流,Nest路由处理程序更加强大,Nest 将自动订阅下面的源并获取最后发出的值(在流完成后)。
@Get() findAll(): Observable<any[]> { return of([]); }
DTO
DTO是什么
数据传输对象(DTO)(Data Transfer Object),是一种设计模式之间传输数据的软件应用系统。数据传输目标往往是数据访问对象从数据库中检索数据。数据传输对象与数据交互对象或数据访问对象之间的差异是一个以不具有任何行为除了存储和检索的数据(访问和存取器)。
简单可以理解为,DTO本身像是一个指南,当在使用API时,方便了解请求期望的数据类型以及返回的数据对象。
DTO是一个对象,它定义了如何通过网络发送数据。我们可以通过使用 TypeScript 接口(Interface)或简单的类(Class)来定义 DTO 模式。有趣的是,我们在这里推荐使用类。为什么?类是 JavaScript ES6 标准的一部分,因此它们在编译后的 JavaScript 中被保留为实际实体。另一方面,由于 TypeScript 接口在转换过程中被删除,所以 Nest 不能在运行时引用它们。这一点很重要,因为诸如管道(Pipe)之类的特性为在运行时访问变量的元类型提供更多的可能性。
/* create-cat.dto.ts */ export class CreateCatDto { readonly name: string; readonly age: number; readonly breed: string; }
@Post() async create(@Body() createCatDto: CreateCatDto) { return 'This action adds a new cat'; }
- 为什么不直接使用interface来定义DTO而是使用class,因为typescript在编译之后会删除interface
- 为什么不使用实体而是定义一个DTO,因为HTTP请求传参和返回的内容可以采用和数据库中保存的内容不同的格式。
一个完整的控制器路由例子
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`; } }
小结
总体而言,控制器就是对请求的api路由的一个匹配,然后对应上相应的路由之后,再去用相应的服务去处理。在控制器处理的过程中可以对请求参数进行一些处理。遵循单一原则,只做一件事情。
加载全部内容