Nest 控制器

iShot2021-09-21 09.01.59

如上图所示的这样,控制器是用来处理客户端传进来的HTTP请求之后再向客户端返回响应数据的。

控制器通过HTTP request接受应用的特殊请求,但是有很多个控制器,因而需要路由机制来控制这个请求是哪个控制器接受的。一般控制器里有多个路由,每一个路由有自己要干的事情

控制器基本创建需要两样东西:类+装饰器,其中装饰器可以把类、元数据相关联,创建路由映射让请求绑定到控制器

路由

创建路由的关键字是@Controller,路由路径前缀随意设置,比如说wee

import { Controller, Get } from '@nestjs/common';

@Controller('wee')
export class WeeController {
    @Get()
    findall(): string {
        return 'Hello Wibus!'
    }
}

使用 CLI 创建控制器: nest g controller controller-name

通过访问 http://localhost:3000/wee/ 可以看到返回了Hello Wibus!而这串代码到底是干嘛的?

@Get()可以为请求的特定端点创建处理程序,端点对应于 HTTP 请求方法(在本例中为 GET )和路由路径(如 GET /wee )。如果我改成@Get('hello')的话,那你需要访问 http://localhost:3000/wee/hello 来看到这句话了,@Controller('wee')可以认为是路径前缀的设置,而@Get就是装饰器

image-20210921092520360

什么是路由路径 ? 一个处理程序的路由路径是通过连接为控制器 (Controller) 声明的(可选)前缀和请求装饰器中指定的任何路径来确定的。

当我们对这个端点发出HTTP请求的时候,Nest会把这个请求路由到我们的findall()方法,但是要说明的是findall是一个自定义方法。而我们必须声明一个绑定到路由上的函数,虽然Nest不会赋予特别意义(甚至是任何意义都不赋予

这个函数可以返回200状态码和其他的响应,但是从我们看来似乎只有一个string字符串,因为Next将会使用两种不同操作响应选项

  • 标准(推荐)

    使用这个内置方法,当请求处理程序返回一个 JavaScript 对象或数组时,它将自动序列化为 JSON。但是,当它返回一个 JavaScript 基本类型(例如string、number、boolean)时, Nest 将只发送值,而不尝试序列化它。这使响应处理变得简单:只需要返回值,其余的由 Nest 负责。

  • 类库特有的

    我们可以在函数签名处通过 @Res() 注入类库特定的响应对象(例如, Express)。使用此方法,你就能使用由该响应对象暴露的原生响应处理函数。例如,使用 Express,您可以使用 response.status(200).send() 构建响应

其实我没看懂()我只知道能用就行,理得它多少

image-20210921093605662

Request

有时我们需要访问客户端的更多请求细节,根据上面的路由代码,加上Express。我们可以在处理函数当中使用@Req()装饰器,它会让nest把请求对象注入处理程序

import { Controller, Get, Req } from '@nestjs/common';
import { Request } from 'express';

@Controller('wee')
export class WeeController {
    @Get('hello')
    findall(@Req() request: Request): string {
        return 'Hello Wibus!'
    }
}

对比与之前的代码,新增了@Req() request: Request这一句话,Request代表HTTP请求,详细的在这里 https://expressjs.com/en/api.html#req

在多数情况下,不必手动获取它们。 我们可以使用专用的装饰器,比如开箱即用的 @Body()@Query() (?从这里我开始看不太懂了

@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

资源

在上面我们通过@Get()创建了一个端点来获取wee的数据。但是一般来讲我们还要多一个创建新数据的端点,这个时候就需要用@Post()

import { Controller, Get, Post } from '@nestjs/common';

@Controller('wee')
export class WeeController {
    // POST路由
    @Post()
    create(): string{
        return 'This action will add a new data'
    }

    // Get路由
    @Get('hello')
    findall(): string {
        return 'Hello Wibus!'
    }
}

就这么简单。 Nest 为所有标准的 HTTP 方法提供了相应的装饰器:@Put()@Delete()@Patch()@Options()、以及 @Head()

此外,@All() 则用于定义一个用于处理所有 HTTP 请求方法的处理程序。

export class WeeController {
    @All()
    findall(): string {
        return 'Hello Wibus!'
    }
}

路由通配符

路由同样支持模式匹配。例如,星号被用作通配符,将匹配任何字符组合

@Get('h*llo')
findall(): string {
    return 'Hello Wibus!'
}

这样的话,他将会匹配abcdab_cdabecd 等。字符 ?+* 以及 () 是它们的正则表达式对应项的子集。连字符(-) 和点(.)按字符串路径逐字解析。

image-20210921105008043

状态码

一般来讲,请求都会返回200,当然我们可以添加一个装饰器来改变响应状态码

@Get('h*llo')
@HttpCode(404)
findall(): string {
    return 'Hello Wibus!'
}

image-20210921105208095

Headers

如果要指定响应头,使用@header()装饰器来修改

@Get('h*llo')
@Header('Cache-Control', 'none')
findall(): string {
    return 'Hello Wibus!'
}

重定向

@Redirect() 装饰器有两个可选参数,urlstatusCode。 如果省略,则 statusCode 默认为 302

@Get()
@Redirect('https://nestjs.com', 302)

路由参数

如果需要接受dynamic data作为请求的一部分时(如 http://localhost:3000/wee/1 )带有静态路径的路由将无法工作,也就是说我们目前所讲的用法并没有这种用法,这个时候我们需要在路由路径当中添加路由参数表计,就像这样

@Controller('wee')
export class WeeController {
    @Get('h*llo/:id')
    findall(@Param() params): string {
        return 'Hello Wibus! ID: ' + params.id
    }
}

image-20210921134905604

@Param() 用于修饰一个方法的参数(上面示例中的 params),并在该方法内将路由参数作为被修饰的方法参数的属性。如上面的代码所示,我们可以通过引用 params.id来访问(路由路径中的) id 参数。 您还可以将特定的参数标记传递给装饰器,然后在方法主体中按参数名称直接引用路由参数。

@Get(':id')
findOne(@Param('id') id): string {
  return `This action returns a #${id} cat`;
}

image-20210921134702765

请求负载

在前文中的@Post()并没有接受任何参数,这个时候需要用@Body()来解决这个问题

以下是我不知道在说啥的东西:

首先(如果您使用 TypeScript),我们需要确定 DTO(数据传输对象)模式。DTO是一个对象,它定义了如何通过网络发送数据。我们可以通过使用 TypeScript 接口(Interface)或简单的类(Class)来定义 DTO 模式。有趣的是,我们在这里推荐使用

类是 JavaScript ES6 标准的一部分,因此它们在编译后的 JavaScript 中被保留为实际实体。另一方面,由于 TypeScript 接口在转换过程中被删除,所以 Nest 不能在运行时引用它们。这一点很重要,因为诸如管道(Pipe)之类的特性为在运行时访问变量的元类型提供更多的可能性。

export class CreateCatDto {
    readonly name: string;
    readonly age: number;
}
export class WeeController {
    @Post()
    @HttpCode(200)
    create(@Body() createCatDto: CreateCatDto): string{
        return `name:${createCatDto.name}, age:${createCatDto.age}`;
    }
}

image-20210921153052842