当前位置: 首页 > 后端技术 > Node.js

Nestjs自译中文文档(二)

时间:2023-04-03 19:02:52 Node.js

Nestjs中文文档(二):控制器版本:6.10.14控制器负责处理传入的请求,并将响应返回给客户端。控制器的目的是接收特定于应用程序的请求。路由机制控制哪个控制器接收哪些请求。通常,每个控制器都有多个路由,不同的路由可以执行不同的动作。为了创建一个基本的控制器,我们使用类和装饰器。装饰器将类与所需的元数据相关联,并使Nest能够创建路由映射(将请求绑定到适当的控制器)。路由在下面的示例中,我们将使用@Controller()装饰器,它是定义基本控制器所必需的。我们将为猫指定一个可选的路由路径前缀。在@Controller()装饰器中使用路径前缀可以让我们轻松地对一组相关的路由进行分组,并最大限度地减少代码重复。例如,我们可以选择对一组路由进行分组,这些路由与客户实体类的交互在路由/客户下进行管理。在这种情况下,我们可以在@Controller()装饰器中指定路径前缀客户,这样我们就不必为文件中的每个路由重复该部分路径@Controller('cats')exportclassCatsController{@Get()findAll():string{return'这个动作返回所有的猫';}}要使用CLI创建控制器,只需执行nestgcontrollercats命令。findAll()方法之前的@Get()装饰器告诉Nest对HTTP请求进行特殊处理。装饰器参数对应HTTP请求方法(本例中为GET)和路由路径。什么是路由路径?处理程序的路由路径是通过将为控制器声明的(可选)前缀与请求装饰器中指定的任何路径连接起来确定的。由于我们已经为每个路由(cats)声明了一个前缀并且没有在装饰器中添加任何路径信息,Nest会将GET/cats请求映射到这个处理程序。如前所述,路径包括可选的控制器路径前缀和请求方法装饰器中声明的任何路径字符串。例如,customers的路径前缀结合修饰的@Get('profile')会生成Get/customers/profile等请求的路由映射在上面的例子中,当这个控制器发出GET请求时,Nest会路由请求用户定义的findAll()方法。请注意,我们在这里选择的方法名称是完全任意的。显然,我们必须声明一个方法来绑定路由,但Nest无法理解所选择的方法名称。也就是说,方法名与路由路径无关。此方法将返回200状态代码和关联的响应,在本例中只是一个字符串。为什么?为了解释,我们将首先介绍Nest使用两种不同的选项来操纵响应的概念。说明Standard使用此内置方法,当请求处理程序返回JavaScript对象或数组时,它将自动序列化为JSON。然而,当它返回一个JavaScript基本类型(例如字符串、数字、布尔值)时,Nest将只发送值而不尝试序列化它。这使得响应处理变得简单:只需返回值,Nest将处理其余部分。此外,除了使用201的POST请求外,默认情况下响应始终具有状态代码200。我们可以通过在处理程序级别添加@HttpCode装饰来轻松更改此行为(请参阅状态代码)。特定于库我们可以使用特定于库(例如Express)的响应对象,该对象可以使用方法处理程序签名中的@Res()装饰器(例如findAll(@Res()response))注入。使用这种方法,您可以(并且有能力)使用此对象公开的本机响应处理方法。例如,使用Express,您可以使用类似response.status(200.send()Warning:Cannotusebothmethodsatthesametime.Nestdetectswhenahandleruses@Res()or@Next(),表明你选择了Library-specific选项。如果两种方法同时使用,这个Standard选项会自动禁用,不再按预期工作。Nestdecorateswithparameters当同时使用类装饰器响应请求和参数装饰器时request类装饰器会失败,这类似于邻近原则。请求对象处理程序通常需要访问客户端请求的详细信息。Nest提供对底层平台的请求对象的访问(默认为Express)。我们可以指示Nest注入请求对象,从而访问它,方法是将@Req()装饰器添加到流程参数import{Controller,Get,Req}from'@nestjs/common';import{Request}from'express';@Controller('cats')exportclassCatsController{@Get()findAll(@Req()request:Request):string{return'这个动作返回所有的猫';}}Tips:为了更好的使用express(如上request:request参数示例所示),请安装@types/express包获取提示。请求对象表示一个HTTP请求,并具有请求查询字符串、参数、HTTP标头和文字的属性。在大多数情况下,不需要手动获取这些属性。我们可以使用现成的专用装饰器,如@Body()或@Query()。下面是提供的装饰器列表以及它们所代表的纯粹特定于平台的对象。装饰器对应对象@Request()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为了与Express和fastfy等底层HTTP平台上的类型兼容,Nest提供了@Res()和@Response()装饰器。@Res()只是@Response()的别名。两者都直接暴露底层原生平台响应对象接口。使用它们时,您还应该导入底层库的类型(例如,@types/express)以充分利用它们。请注意,当您在方法处理程序中注入@Res()或@Response()时,您将Nest放入该处理程序的库特定模式中,并负责管理响应。执行此操作时,必须通过调用响应对象(如res.json(…)或res.send(…))发送某种响应,否则HTTP服务器将挂起提示:Doyouwanttolearnhowtomake你自己的装饰师?(稍后学习,暂未翻译)浏览https://docs.nestjs.com/custom-decorators资源之前,我们使用@Get装饰器通过get方法访问资源,现在我们来尝试使用post访问它:import{Controller,Get,Post}from'@nestjs/common';@Controller('cats')exportclassCatsController{@Post()create():string{return'Thisactionaddsanewcat';}@Get()findAll():string{return'这个动作返回所有的猫';}}呜呜呜(尖叫~),这也太简单了吧。Nest以与请求装饰器相同的方式提供标准HTTP的其余部分-@Put()、@Delete()、@Patch()、@Options()、@Head()和@All()。每个代表其各自的HTTP请求方法。路由通配符也支持通配符模式,例如星号作为通配符,会匹配任意字符组合。@Get('ab*cd')findAll(){return'Thisrouteusesawildcard';}这个ab*cd会匹配abcd,ab_cd,abecd等,?,+,*,()也允许在路由路径。状态代码如前所述,默认响应状态代码始终为200,除了post为201。我们可以轻松添加@HttpCode装饰器来改变默认行为@Post()@HttpCode(204)create(){return'Thisactionaddsanewcat';}先导包:importHttpCodefrom@nestjs/common标头信息要指定自定义响应标头,您可以使用@header()装饰器或库特定的响应对象(并直接调用res.header())@Post()@Header('Cache-Control','none')create(){return'Thisactionaddsanewcat';}Redirect如果要重定向到某个URL,可以使用@Redirect()装饰器,也可以直接使用具体的响应对象如:res.redirect()@Get()@Redirect('https://nestjs.com',301)有时需要动态传递参数,返回时只需要遵循如下结构即可:{"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/'};}}路由参数当它需要接受动态数据作为请求的一部分时(例如,get/cats/1以获取id为1的猫),具有静态路径的路由将不起作用。为了定义带参数的路由,我们可以在路由路径中添加路由参数标记,以捕获请求URL中该位置的动态值。下面@Get()装饰器示例中的路由参数标记演示了这种用法。可以使用@Param()装饰器访问以这种方式声明的路由参数,该装饰器应相应地添加到方法中。@Get(':id')findOne(@Param()params):string{console.log(params.id);return`Thisactionreturnsa#${params.id}cat`;}@Param()用于装饰方法参数(上面示例中的params),并使路由参数可用作装饰方法参数的属性方法体。如上代码所示,我们可以通过引用params.id来访问id参数,也可以将具体的参数标记传递给装饰器,然后在方法体中直接通过名称引用路由参数。@Get(':id')findOne(@Param('id')id):string{return`这个动作返回一个#${id}cat`;}子域路由@Controller装饰器可以使用host选项,需要passing传入请求的HTTP主机匹配某个特定值。@Controller({host:'admin.example.com'})exportclassAdminController{@Get()index():string{return'Adminpage';}}警告:由于fastfy不支持嵌套路由器,因此在使用子域路由时,应改用(默认)Express适配器。与路由路径类似,hosts选项可以使用令牌来捕获主机名中该位置的动态值。下面@Controller()装饰器示例中的主机参数标记演示了这种用法。可以使用@HostParam()装饰器访问以这种方式声明的主机参数,该装饰器应添加到方法签名中。@Controller({host:':account.example.com'})exportclassAccountController{@Get()getInfo(@HostParam('account')account:string){returnaccount;}}异步性我们喜欢现代JavaScript,而且我们知道数据提取大多是异步的。这就是Nest支持异步函数并且运行良好的原因。每个异步函数都必须返回一个承诺。这意味着您可以返回一个Nest能够自行解析的值。让我们看看这个例子。@Get()asyncfindAll():Promise{return[];}上面的代码完全有效!此外,Nest路由处理程序能够返回RxJS可观察流,因此它们更加强大。Nest将自动订阅下面的源并获取最后发出的值(一旦流完成)@Get()findAll():Observable{returnof([]);}以上两种方法都有效,您可以使用适合您要求的任何方法请求请求的有效负载我们之前的POST路由处理程序示例不接受任何客户端参数。让我们通过在此处添加@Body()装饰器来解决此问题。但首先(如果您使用TypeScript),我们需要确定DTO(数据传输对象)架构。DTO是定义数据在线发送方式的对象。我们可以使用TypeScript接口或简单类来确定DTO模式。有趣的是,我们建议在这里使用类。为什么?类是JavaScriptES6标准的一部分,因此,它们在编译后的JavaScript中作为真实实体保留。由于TypeScript接口在编译期间被删除,Nest无法在运行时引用它们,这很重要,因为管道等功能可以在运行时访问变量的元类型。让我们创建CreateCatDto类exportclassCreateCatDto{readonlyname:string;只读年龄:数字;readonlybreed:string;}它只有三个基本属性。之后我们就可以在里面使用新创建的DTOCatsController了:@Post()asynccreate(@Body()createCatDto:CreateCatDto){return'Thisactionaddsanewcat';}本节所有demo如下:使用可用装饰器创建基本控制器的示例。该控制器公开了两种访问和操作内部数据的方法。import{Controller,Get,Query,Post,Body,Put,Param,Delete}from'@nestjs/common';import{CreateCatDto,UpdateCatDto,ListAllEntities}from'./dto';@Controller('cats')导出类CatsController{@Post()create(@Body()createCatDto:CreateCatDto){return'这个动作添加了一只新猫';}@Get()findAll(@Query()query:ListAllEntities){return`此操作返回所有猫(限制:${query.limit}项)`;}@Get(':id')findOne(@Param('id')id:string){return`这个动作返回一个#${id}cat`;}@Put(':id')update(@Param('id')id:string,@Body()updateCatDto:UpdateCatDto){return`这个动作更新了一只#${id}cat`;}@Delete(':id')remove(@Param('id')id:string){return`这个动作删除了一只#${id}cat`;}}在完全定义了上面的控制器之后,Nest仍然不知道CatsController类是否存在,所以不会创建这个类的实例。控制器总是属于一个模块,这就是我们的控制器数组包含在@Module()装饰器中的原因。由于除了根AppModule之外我们没有定义任何其他模块,我们将使用它来导入CatsController:@Module({controllers:[CatsController],})exportclassAppModule{}我们使用@Module()装饰器将元数据附加到模块类,Nest现在可以轻松反映必须安装的控制器。附言使用库功能到目前为止,我们已经讨论了处理响应的Nest标准方法。处理响应的第二种方法是使用特定于库的(快速)响应对象。为了注入特定的响应对象,我们需要使用@Res()装饰器,如下(可以对比一下和Nest标准处理方式的区别)import{Controller,Get,Post,Res,HttpStatus}from'@nestjs/common';import{Response}from'express';@Controller('cats')exportclassCatsController{@Post()create(@Res()res:Response){res.status(HttpStatus.CREATED).send();}@Get()findAll(@Res()res:Response){res.status(HttpStatus.OK).json([]);虽然这种方法是有效的,并且实际上通过提供对响应对象的完全控制(标头操作、特定于库的特征等)在某些方面允许更大的灵活性,但应谨慎使用。总的来说,这种方法不太明确并且确实有一些缺点。主要缺点是与依赖Nest标准响应处理的功能不兼容,例如拦截器和@HttpCode()装饰器。此外,您的代码可能依赖于平台(因为底层库在响应对象上可能有不同的api),并且难以测试(您必须模拟响应对象等)。因此,在可能的情况下,应始终首选Nest标准方法。