Controller 的作用主要是接受处理请求和向客户端返回处理后的响应数据。在 Controller 中会包含很多的路由,而路由主要是执行不同的业务逻辑处理。
我们在编写 Controller 的时候,可以使用@Controller()
装饰器来定义对应的 Controller。在装饰器中我们可以使用路径前缀来为路由分组,从而最大限度地减少重复代码。例如我们可以把商品信息管理的相关路由都放在一个控制器里面,具体代码如下:
import { Controller, Get, Post } from "@nestjs/common";
@Controller("commodity")
export class CommodityController {
@Get()
getCommodity(): string {
return "获取商品";
}
@Post("/save")
saveCommodity(): string {
return "保存商品";
}
}
在上述的代码中,我们声明了commodity
为前缀的控制器,所以 NestJs 在帮我们生成路由的时候都会在路由地址最前面加上commodity
关键字。
而具体路由生成是根据控制器代码块里面的请求装饰器来决定的,就比如上述的代码来说,我们声明了两个接收请求的方法,一个是Get
请求,并且采用默认路由方式,而另外是Post
请求,并且声明了具体路径地址/save
。
所以 NestJs 会帮我生产如下两个请求路径:GET /commodity
和 POST /commodity/save
。这样我们向这两个地址发送请求的时候,理由都会走到这两个路由中做后续的业务逻辑处理。
这样我们就可以知道 NestJs 的路径生产规则是:前缀 + 具体路径
。
注意:在 NestJS 中,采用 NestJs 内置的请求方法时需要注意 POST 的状态码是 201,其他的状态码都是 200。
处理程序通常需要访问客户端发送过来的请求数据,而 NestJs 提供对底层平台(默认为 Express)的请求对象的访问,而要使用的时候我们可以使用@Req
装饰器来获取对象。具体代码如下:
@Get()
getCommodityList(@Req() request: Request): string {
return '获取商品列表'
}
注意:在上述代码中我们使用了 Request 对象,而这个对象在 NestJS 中是没有对这个对象的声明,所以需要我们安装@types/express。
Request 这个对象里面有很多的信息,例如有请求的 HTTP 标头、正文、参数等等。在大部分情况下我们不用手动获取这些属性,因为 NestJS 帮我门写好了对应的装饰器。具体的装饰器如下表:
装饰器 | 对应对象和属性 |
---|---|
@Request(), @Req() | request 对象 |
@Response(), @Res()* | response 对象 |
@Next() | next 对象 |
@Session() | request 对象中的 session 属性 |
@Param(key?: string) | request 对象中的 params 对象 |
@Body(key?: string) | request 对象的 body 对象 |
@Query(key?: string) | request 对象中的 query 对象 |
@Headers(name?: string) | request 对象中的 headers 对象 |
@Ip() | request 对象中的 IP 信息 属性 |
@HostParam() | request 对象中的主机信息属性 |
注意:在 NestJs 中,程序响应处理它已经帮我们做好了处理,我们只要直接返回数据就可以而无需做什么特殊处理,假如你在方法中注入了@Req()或者@Response(),就相当于将 Nest 置于某个特殊平台的模式下,这样响应就需要你自己进行处理,即必须通过调用对象 response(res.json()或者 res.send())来发出响应,否则 HTTP 服务器将会挂起。
在 NestJs 中提供了标准的 HTTP 方法的装饰器:@Get()
、@Post()
、@Put()
、@Delete()
、@Patch()
、@Options()
和@Head()
。
在路由通配符中字符 ?、+、* 和 () 是其正则表达式同应项的子集。
通配符的具体例子如下:
// 匹配/random.text的请求路径
@Get('/random.text')
getTextInfo() {
return '获取text文件'
}
// 匹配geinfo和getinfo的请求路径,即t字符允许出现一次或没有
@Get('/get?info')
getInfo() {
return '?通配符'
}
// 匹配getabc或者gettabc的请求路径,即t字符最少出现一次和出现多次
@Get('/get+abc')
getAbc() {
return '+通配符'
}
// 匹配/abe 和 /abcde
@Get('/ab(cd)?e')
getAbcd() {
return '()通配符'
}
// 匹配以get开头的所有请求路径
@Get('/get*')
getCommodityList(@Req() request: Request): string {
return '*通配符'
}
在通配符中*
通配符的匹配深度是最大的,所以在使用*
通配符的时候最好放在最后一个,因为在 NestJs 中路由是由上而下进行匹配的。
如前所述,默认情况下响应状态代码始终为 200,POST 请求除外,该代码为 201。在 NestJS 中我们可以使用@HttpCode()
装饰器来设置状态码。
在 NestJs 中我们想要自定义响应头的话可以使用@Header()
装饰器或者使用响应对象来进行设置。具体代码如下:
@Put()
@Header('Cache-Control', 'none')
updateCommodity(): string { return '修改商品' }
在 NestJs 中我们可以使用@Redirect()
装饰器来实现重定向到具体的 URL 上。我们也可以使用响应对象来实现重定向的功能。
其中@Redirect()
装饰器可以接受两个参数,一个是重定向的 URL,另外一个是响应的状态码。
有时候我们重定向的地址是根据有些参数判断后进行动态跳转的,我们只要这样做就可以。
@Get('search')
@Redirect('https://biyinig.com', 302)
getSearch(@Query('searchType') version: string) {
if (version && version === 'baidu') {
return { url: 'https://www.baidu.com' };
}
}
@Controller
装饰器可以接受指定路由作为参数外,还可以接收host
对象来声明其他的主机地址,作为真实的请求地址。具体的实例如下:
@Controller({ host: "admin.example.com" })
export class AdminController {
@Get()
index(): string {
return "Admin page";
}
}
当我们声明好控制器以后,NestJs 仍然不知道该控制器的 CatsController 存在,因此不会创建此类的实例。
所以我们可以在AppModule
中添加我们声明的控制器。具体代码如下:
import { CommodityController } from "./controller/commodity.controller";
import { Module } from "@nestjs/common";
import { AppController } from "./app.controller";
import { AppService } from "./app.service";
@Module({
imports: [],
controllers: [AppController, CommodityController],
providers: [AppService],
})
export class AppModule {}
完成上述的控制器注入后,我们启动程序时就会把对应的控制器实例创建出来,从而就可以访问到对应的接口。