NestJs 控制器 Controller
在 NestJS 中,Controller 是应用程序的一部分,负责处理传入的请求并返回响应。
Controller 可以被视为处理特定 URL 路径的模块,它负责执行与请求相关的操作。路由机制控制哪个控制器接收哪些请求。通常,每个控制器有多个路由,不同的路由可以执行不同的操作。
在 NestJS 的 Controller 中,我们可以使用修饰器(decorators)来定义路由和请求方法。修饰器可以帮助我们将逻辑关联到特定的 URL 路径上。Controller 类中定义的方法接收请求和响应对象的参数,从而让我们能够访问请求的数据并返回响应。一个 Controller 类通常包含多个路由,每个路由都能够处理特定的 HTTP 请求方法(GET、POST、PUT等)。
路由
cats.controller.ts
在下面的示例中,我们创建了一个名为 CatsController
的 Controller 类,并使用 @Controller()
装饰器来指定该 Controller 处理的 URL 路径是 cats
。然后,我们使用 @Get()
和 @Post()
装饰器来定义了两个路由分别处理 GET 和 POST 请求。
import { Controller, Get, Post, Body } from '@nestjs/common';
@Controller('cats')
export class CatsController {
@Get()
findAll():string {
// 处理 GET /cats 请求
return '获取cat列表';
}
@Post()
create():string {
// 处理 POST /cats 请求
return '添加cat';
}
}
findAll()
方法之前的 @Get()
装饰器告诉 Nest 该方法所使用的请求方法(在本例中为 GET )和路由路径,由于我们已经为每个 route(cats) 声明了一个前缀,并且没有在装饰器中添加任何路由信息,因此 Nest 会将 GET /cats 请求映射到此处理程序。例如,装饰器 @Get('get')
为 GET /cats/get
请求生成路由映射。
由此可知,Nest 会将 POST /cats
请求映射到 create()
方法。
什么是路由路径 ? 一个处理程序的路由路径是通过连接为控制器 (Controller) 声明的(可选)前缀和请求装饰器中指定的任何路径来确定的。
请求方式
在NestJS中,NestJS为所有标准的 HTTP 方法提供了相应的装饰器:@Put()
、@Delete()
、@Patch()
、@Options()
、@Head()
和@All()
,其中@All()
用于将所有的HTTP请求方法与路由处理程序关联起来,当收到任何HTTP请求时,无论是GET、POST、PUT还是DELETE等,都将调用被装饰的路由处理程序。
请求 Request
在 NestJS 中,request是指从客户端发送到服务器的HTTP请求的对象(默认为 Express
),该对象提供了访问客户端请求的丰富信息和处理能力,下方示例在处理函数的签名中使用@Req()
和@Body()
装饰器,这将会把请求体中的数据绑定到参数中,使得我们可以更加灵活和方便地处理和响应客户端的请求。
cats.controller.ts
import { Controller, Get, Post, Body } from '@nestjs/common';
@Controller('cats')
export class CatsController {
@Get()
findAll(@Req() request:Request):string {
return '获取cat列表';
}
@Post()
create(@Body() cat):string {
return `添加cat:${cat.name}`;
}
}
通过NestJS中的request对象,我们可以访问客户端发送的请求的各种信息。这些信息包括请求的路径、HTTP方法、请求头、查询参数、请求体等。
下面是 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 |
NestJS中的request对象可以通过依赖注入的方式在控制器、拦截器、管道等各个模块中使用。我们可以将其作为参数传递给处理函数,或者使用装饰器获取它。
- 在控制器中,我们可以使用request对象来读取请求的信息,例如获取查询参数、请求体等,并根据这些信息执行相应的操作。我们还可以使用request对象来设置响应的状态码、头部、内容等。
- 在拦截器中,我们可以使用request对象来修改请求的信息或者根据请求的信息进行处理。例如,我们可以在拦截器中对请求进行验证、修改请求的路径等操作。
- 在管道中,我们可以使用request对象来验证请求的内容、进行数据转换等操作。例如,我们可以在管道中根据请求的内容来验证用户的身份、检查请求的数据是否合法等。
为了与底层 HTTP 平台(例如,Express
和 Fastify
)之间的类型兼容, Nest 提供了 @Res()
和 @Response()
装饰器。@Res()
只是 @Response()
的别名。两者都直接暴露了底层平台的 response 对象接口。在使用它们时,您还应该导入底层库的类型声明(如:@types/express
)以充分利用它们。需要注意的是,在请求处理函数中注入 @Res()
或 @Response()
时,会将 Nest 置于该处理函数的特定于库(Library-specific mode)的模式下,并负责管理响应。这样做时,必须通过调用 response 对象(例如,res.json(…)
或 res.send(…)
)发出某种响应,否则 HTTP 服务器将挂起。
自定义装饰器 TODO
路由通配符
在NestJS中,路由通配符是指通配符路由路径的一部分,用于匹配多个路由。它允许我们创建具有相似路径的多个路由,并将它们归为一类。
NestJS中的路由通配符主要有两种类型:参数化路由和通配符路径。
1. 参数化路由: 参数化路由允许我们将路由路径的特定部分作为参数传递给路由处理程序。这是通过在路径中使用冒号:
来实现的。例如,我们可以使用以下路由路径来匹配不同的用户ID:
@Get('cat/:id')
findOne(@Param('id') id: string): Cat {
// 根据ID获取特定Cat
}
在上面的示例中,/cat/123
和/cat/456
将分别匹配到相同的路由处理程序,并且可以通过id参数来获取不同的cat。
2. 通配符路径: 通配符路径是指使用通配符符号*
匹配路由路径的任意部分。这允许我们处理任意路径的请求。例如,以下路由路径将匹配到所有以ab
开头cd
结尾的路径:
@Get('/ab*cd')
findAll():Cat[] {
// 获取所有Cat
return '这是一个使用了通配符的路由接口';
}
在上述示例中,/abcd
、/ab_cd
和/abecd
等路径都将匹配到相同的路由处理程序。
字符 ? 、+ 、 * 以及 () 是它们的正则表达式对应项的子集。连字符-
和点.
按字符串路径逐字解析。
合理的使用路由通配符可以有效地组织和处理一类具有相似路径的路由。
状态码
在NestJS中,我们可以使用@HttpCode()
装饰器来自定义路由处理程序的HTTP状态码。默认情况下,NestJS会自动根据路由处理程序的返回值来设置适当的状态码。
以下是一些常见的HTTP状态码及其对应的含义:
- 200 OK:请求成功。用于GET请求和非幂等操作(例如POST,PUT和DELETE)的成功响应。
- 201 Created:请求已成功创建新的资源。通常用于创建资源的POST请求。
- 204 No Content:请求成功,但响应不包含任何内容。通常用于DELETE请求或PUT请求,不需要返回任何实体主体的情况。
- 400 Bad Request:请求无效或错误。客户端发送的请求无效,服务器无法处理。
- 401 Unauthorized:请求未经授权。表示需要进行身份验证以访问资源。
- 403 Forbidden:服务器理解请求,但拒绝执行。与401不同,身份验证无法提供访问权限。
- 404 Not Found:请求的资源不存在。
- 500 Internal Server Error:服务器内部错误。表示服务器在处理请求时遇到问题。
如上所述,默认情况下,响应的状态码总是默认为 200,除了 POST 请求(默认响应状态码为 201),我们可以通过在处理函数外添加 @HttpCode(...)
装饰器来轻松更改此行为。
@Post()
@HttpCode(204)
create() {
return 'This action adds a new cat';
}
HttpCode 需要从 @nestjs/common 包导入。
在 NestJS 中,返回的状态码通常是根据请求处理的结果和业务逻辑来确定的。下面是一些常见的处理方式:
1.使用内置的异常类:NestJS 提供了一些内置的异常类,如 HttpException
、BadRequestException
、NotFoundException
等。你可以使用这些异常类来处理不同的情况,并指定相应的状态码。例如,在处理一个未找到资源的请求时,可以抛出一个 NotFoundException
,并设置状态码为 404。
import { NotFoundException } from '@nestjs/common';
// ...
throw new NotFoundException('Resource not found');
// ...
2.自定义异常类:除了使用内置的异常类之外,你还可以自定义异常类来处理特定的情况,并指定相应的状态码。可以继承 HttpException
类,然后在构造函数中指定
状态码和错误消息。
import { HttpException, HttpStatus } from '@nestjs/common';
export class CustomException extends HttpException {
constructor() {
super('Custom exception message', HttpStatus.BAD_REQUEST);
}
}
3.使用装饰器:NestJS 的控制器方法可以使用各种装饰器来指定特定的状态码。例如,使用 @HttpCode
装饰器可以设置响应的状态码。
@Get()
@HttpCode(HttpStatus.CREATED)
async create(): Promise<any> {
// ...
}
4.使用拦截器:你还可以使用拦截器来在请求处理之后修改响应的状态码。可以通过实现一个自定义的拦截器类,并在 intercept()
方法中修改 response 对象的状态码。
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
@Injectable()
export class StatusInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next.handle().pipe(
map(data => {
response.status(201);
return data;
}),
);
}
}
请求头 Headers
在 NestJS 中处理请求时,可以使用 @Headers()
装饰器来获取请求头的值。该装饰器将请求头的值注入到处理程序方法的参数中。
以下是一个示例说明如何使用 @Headers()
装饰器:
import { Controller, Get, Headers } from '@nestjs/common';
@Controller('cats')
export class CatsController {
@Get()
findOne(@Headers() headers: Record<string, string>) {
console.log(headers);
// 打印示例:
// {
// host: 'localhost:3000',
// 'user-agent': 'PostmanRuntime/7.26.5',
// accept: '*/*',
// 'accept-encoding': 'gzip, deflate, br',
// connection: 'keep-alive'
// }
}
}
在上面的例子中,@Headers()
装饰器将请求头的键值对作为参数传递给 findOne()
方法。我们可以在处理程序方法中使用这些请求头信息。在示例中,我们简单地将请求头打印到控制台。
同时也可以使用@Headers()
装饰器来获取特定的请求头。例如:
@Get()
findOne(@Header('host') host: string) {
console.log(host);
// 打印示例:
// 'localhost:3000'
}
请注意,@Headers() 装饰器返回一个对象,其中键是请求头的名称,值是请求头的值。如果有多个相同名称的请求头,则值将作为字符串数组返回。你还可以使用索引访问特定的请求头值,如 headers['user-agent']。
响应头 Header
NestJS 的 @Header()
装饰器可以用来设置响应头,也可以用来获取特定的响应头。
首先,当使用 @Header()
装饰器设置响应头时,你可以将其作为一个装饰器附加到控制器方法上,指定你想要设置的响应头的名称和值。例如:
@Get()
@Header('Cache-Control', 'no-cache')
findOne() {
// ...
return 'This action find a cat';
}
上述代码中,我们使用 @Header()
装饰器将 "Cache-Control"
响应头设置为 "no-cache"
。
其次,在处理请求的控制器方法中,你可以通过使用@Res()
装饰器注入 Response 对象,然后使用response.header()
方法来设置响应头。例如:
@Get()
findAll(@Res() response: Response) {
response.header('Content-Type', 'application/json');
response.header('Cache-Control', 'no-cache');
// ...
return 'Data';
}