Nest.js 控制器

1,570 阅读5分钟

Nest.js控制器用来负责处理传入的请求以及向客户端返回响应。来看看官方的示意图:

路由

路由机制控制哪个控制器接收哪些请求。通常,每个控制器有多个路由,不同的路由可以执行不同的操作。

新建目录controller,然后使用命令行创建控制器user:

nest g controller user

创建完成后,会自动生成如下文件:

默认生成的user.controller.ts内容如下:

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

@Controller('user')
export class UserController {}

其中定义控制器我们需要使用@Controller()装饰器,这是定义基本控制器所必需的。我们可以理解为这是固定的写法。

我们将指定一个路径前缀(可选)user。在@Controller()装饰器中使用路径前缀,它允许我们轻松对一组相关路由进行分组,并减少重复代码。

接下来我们添加一个get方法:

@Controller('user')
export class UserController {

    @Get()
    getUser(): string {
        return "User: my name is nest user";
    }
}

@Get() HTTP 请求方法装饰器告诉Nest为HTTP请求的特定端点创建处理程序。端点对应于HTTP请求方法(在本例中为GET)和路由。

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

处理程序的路由是通过连接为控制器声明的(可选)前缀和请求装饰器中指定的任何路由来确定的。由于我们已经为每个 route(user) 声明了一个前缀,并且没有在装饰器中添加任何路由信息,因此 Nest会将 GET /user请求映射到此处理程序。如上所述,该路由包括可选的控制器路由前缀和请求方法装饰器中声明的任何路由。

我们添加一个路由:

    @Get("age")
    getUserAge(): number {
        return 10;
    }

此时Nest会为请求生成路由映射 GET /use/age。

此时我们在浏览器中访问: http://localhost:3000/user 将会得到下面的错误:

{"statusCode":404,"error":"Not Found","message":"Cannot GET /user"}

这个原因很简单, 我们需要在app.module.ts导入我们新建的控制器:

我们再次访问上面的地址:http://localhost:3000/user

同样的的我们访问:http://localhost:3000/user/age

总结:如果我们在请求装饰器中声明了路由,那么该路由地址就是控制器装饰器前缀+请求装饰器路由(/user/age)。 如果请求装饰器没有声明路由,那么该路由地址就是控制装饰器前缀(/user)。

注意在控制器中路由是按照声明顺序查找的,如果我们声明了两个同名路由,那么只会响应第一个,比如:

    @Get()
    getUser2(): string {
        return "User: my name is nest user2";
    }

    @Get()
    getUser(): string {
        return "User: my name is nest user";
    }

此时,程序没有错误发生,但是访问的时候,只会响应第一个:

通常,我们的后台可以同时响应get和post请求,以上为例,我们创建一个post请求:

    @Post()
    getUser(): string {
        return "User: my name is nest user";
    }

在postman中模拟请求:

Nest以相同的方式提供其余的端点装饰器- @Put() 、 @Delete()、 @Patch()、 @Options()、 @Head()和 @All()。这些表示各自的 HTTP请求方法。

路由通配符

通配符是一种特殊语句,主要用来模糊搜索。字符?、+、*以及()是它们的正则表达式对应项的子集。连字符 (-) 和点 (.) 按字符串路径解析。比如我们有下面的请求:

   @Get("age*")
    getUserAge(): number {
        return 10;
    }

此时路由地址将匹配age后面加任意内容的地址:

具体的可以参考下正则表达式的一些知识。

状态码

默认情况下,Get请求的状态码默认为200,Post请求的状态码为201,如果我们需要改变此行为,那么我们需要使用@HttpCode()装饰器

HttpCode 需要从 @nestjs/common 包导入。

import { Controller, Get, HttpCode } from '@nestjs/common';
    @Get()
    @HttpCode(204)
    getUser(): string {
        return "User: my name is nest user";
    }

Headers

我们可以使用@Header()装饰器来自定义响应头,格式如下:

Header(name: string, value: string)
    @Get()
    @Header("isPhone","true")
    getUser(): string {
        return "User: my name is nest user";
    }

重定向

要将响应重定向到特定的URL,可以使用@Redirect()装饰器:

    @Get("baidu")
    @Redirect('https://www.baidu.com/', 302)
    jumpToBaidu(){
        return { url: 'https://www.baidu.com/home/page/show/pagesetting#msg_setting' };
    }

其中Redirect定义如下

export declare function Redirect(url: string, statusCode?: number): MethodDecorator;

statusCode参数如果省略,则statusCode默认为302。

有时候,我们需要根据一些情况动态确定路由地址,此时我们可以如上面一样返回处理过的地址,其返回格式为:

{
  "url": string,
  "statusCode": number
}

在浏览器请求上面的地址:http://localhost:3000/user/baidu将会自动跳转至我们返回的网页

路由参数

当我们需要接收动态参数作为请求的一部分时,我们可以在路由中添加路由参数标记,以捕获请求 URL 中该位置的动态值。

    @Get(':id')
    getUser(@Param() params): string {
        return `User: my name is nest user${params.id}`;
    }

此时我们访问该路由地址格式为:http://localhost:3000/user/2

使用 @Param()装饰器访问以这种方式声明的路由参数,该装饰器应添加到函数签名中。

我们同样可以将特定的参数标记传递给@Param()装饰器,然后在方法主体中按名称直接引用路由参数。

   @Get(":id")
    getUser(@Param("id") id): string {
        return `User: my name is nest user${id}`;
    }

使用Post请求接收任何客户端参数

我们可以通过@Body()装饰器来完成这个工作。 不过首先我们需要定义一个类,比如User:

export class CreateUserDao {

    // 用户姓名
    readonly name: string;
    // 用户年龄
    readonly age: number;
    // 用户性别
    readonly gender: number;
}

接下来我们在控制器中使用我们定义好的数据类:

    @Post("createuser")
    createUser(@Body() createUserDao: CreateUserDao): string {
        return `this is a new user: ${createUserDao.name}`
    }

如果使用${}形式引用变量,请使用反引号

在postman中模拟请求:

这里我们需要设置Content-Type为application/json。