欢迎继续关注NestJs之旅系列文章MVC说到controller,就不得不说说经典的MVC架构。MVC模式(Model-view-controller)是软件工程中的一种软件架构模式,它将软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。控制器(Controller)——负责转发请求,处理请求,处理后输出响应。视图(View)——界面设计者设计图形界面模型(Model)——数据库查询和业务逻辑。可以看到控制器起着承上启下的作用,是web开发必不可少的一部分。视图和模型不是必须的,原因如下:API项目直接输出JSON数据,不需要渲染页面,没有数据库或复杂的业务逻辑项目,请求处理可以直接在控制器中完成。路由控制器的目的是接收应用程序的特定请求。请求的分发是基于路由机制实现的。通常,每个控制器都有多个路由,不同的路由可以执行不同的操作。我们使用类和装饰器来创建一个基本的控制器。装饰器将类与所需的元数据相关联,并使Nest能够创建路由映射(将请求绑定到适当的控制器)。控制器定义使用@Controller装饰器来定义控制器,传入一个可选的路由前缀以将控制器绑定到该前缀。import{Controller,Get}from'@nestjs/common';@Controller('cats')exportclassCatsController{@Get('list')findAll():string{return'这个动作返回所有的猫';}@Get('show')fineOne():string{return'一只猫';}@Get()index():string{返回'index';}}上述例程将生成以下路由:GET/cats/listCatsController::findAll方法处理GET/cats/showCatsController::show方法处理GET/catsCatsController::index方法上述例程使用@Get装饰器,所以它只能处理GET请求。下面是支持的请求方法及其对应关系DecoratorforRequestMethodDecoratorNameDescriptionGET@Get匹配GET请求POST@Post匹配POST请求PUT@Put匹配PUT请求HEAD@Head匹配HEAD请求DELETE@Delete匹配DELETE请求OPTIONS@OptionsmatchesOPTIONSrequest-@AllmatchesallRequestMethodDynamicRouting上面的路由方法接收到的参数是固定的,所以只能匹配固定的请求。如果路由地址是动态变化的(路由地址是指请求的路径,不包括QueryString),则上述路由定义方法无法正常工作。NestJs支持基于路径的路由定义,使用方法如下:import{@Controller,Get}from'@nestjs/common';@Controller('cats')classCatsController{@Get(':id')findOne(@Param()params):string{console.log(params.id);return`此操作返回#${params.id}cat`;}}请求动态路由时,比如/cats/catID(因为猫ID是路径部分,所以路径是变化的),params.id就是猫ID,做过Vue或者React开发的读者应该很熟悉写法如下:路由定义/user/:userId/orders/:orderId页面地址/user/1/orders/2访问上述页面会产生如下参数:userId=>1orderId=>2NestJs在这方面是一致的。请求参数在上面的例子中,我们使用了@Params来读取请求路径上的动态参数。NestJs也支持以下装饰器获取不同的请求参数装饰器名称底层对象描述@Request()req原始请求对象@Response()res原始响应对象@Param(key?:string)req.paramsorreq.params[key]路径参数@Body(key?:string)req.body或req.body[key]请求体,支持表单或JSON@Query(key?:string)req.query或req.query[key]请求链接查询字符串@Headers(name?:string)req.headersorreq.headers[key]请求头请求体在POST/PUT/PATCH请求中会包含请求体,NestJs可以通过@Body装饰器自动获取请求数据.例如下面的代码:@Controller('user')exportclassAppController{constructor(privatereadonlyappService:AppService){}@Post()findAll(@Body()data:any){returndata;}}上面的例程会原样输出请求内容。请求体绑定SpringBoot中的@RequestBody注解可以直接绑定给定的POJO对象,实现请求参数的自动注入。在NestJs中,也支持这个特性。定义DTO对象导出类UserLoginDTO{readonlyusername:string;readonlypassword:string;}定义控制器@Controller('users')classUserController(){@Post('login')login(@Body()userLoginDTO:UserLoginDTO){console.log(userLoginDTO.username,userLoginDTO.password);}}可以看到和SpringBoot的开发体验差不多。响应头如果需要输出响应头,可以使用@Header(name:string,value:string)装饰器来处理。请注意:响应头使用了@Header()装饰器,请求头使用了@Headers()装饰器,最后是s的区别!@Controller('users')classUserController{@Head(':id')@Header('x-version','1.0.0')functionhead(@Param('id')id:number){}响应statuscode从responsebody的设计上可以发现一个问题,既然不建议直接操作response对象,如果我们需要输出responsestatuscode怎么办?NestJs也为我们提供了解决方案。使用@HttpCode(statusCode:number)装饰器设置响应状态代码。在RestfulAPI设计中,DELETE请求应该返回204NoContent状态码,如下代码所示:@Controller('users')classUserController{@DELETE(":id")@HttpCode(204)delete(@Param('id')id:number){//删除成功不需要返回数据}}响应体在express或者开发中,响应内容是我们手动赋值或者输出的,但是在NestJs中可以直接根据路由函数的返回值类型自动识别响应体类型。NestJs支持以下格式的响应:TS类型响应类型响应格式stringtext/htmlobjectJSONapplication/jsonarrayJSONapplication/jsonnullNone(响应体长度为0)NoneundefinedNone(响应体长度为0)NonePromise<*>根据Promise返回的结果类型确定(规则如上)——异步路由函数在前面的例子中,我们所有的路由处理函数都是同步的,但是在实际开发中基本不可能。一旦涉及到数据库访问和缓存访问,就会有IO。有IO的地方就会有异步。NestJs天生就完美支持异步。异步编程有两种方法:Promise@Get()asyncfindAll():Promise
