Skip to content

Nest.js 简介

Nest.js 是一个用 TypeScript 构建高效、可扩展的服务器端应用程序的框架。它结合了 TypeScript 的优势和 Angular 的设计理念,提供了一种优雅而强大的开发体验。Nest.js 基于模块化的架构,拥有强大的依赖注入、模块化、和可测试性等特性,使得构建复杂的应用程序变得更加容易。

安装 Nest.js CLI

要开始使用 Nest.js,首先需要安装 Nest.js 的命令行工具(CLI)。可以通过以下命令进行安装:

shell
npm install -g @nestjs/cli

安装完成后,我们就可以使用 nest 命令来创建新的 Nest.js 项目了。

创建 Nest.js 项目

通过以下命令创建一个新的 Nest.js 项目:

shell
nest new project-name

这将在当前目录下创建一个名为 project-name 的新项目,并自动初始化一些基本的文件和配置。

目录结构

目录结构很简洁,在创建项目之后,目前只有一个根模块(App),后续会创建出很多各种模块 User/Order/... 等等,NestJS 可以说是通过"模块"来管理整个应用的。

文件名描述
main.ts入口文件,后续全局性的配置会在这里配置。
app.controller.ts定义接口的地方,前端请求过来,最先到达这里。
app.module.ts应用的根模块,后续会创建很多模块,都要在此进行管理
app.service.ts管理数据库的 CRUD 操作
app.controller.spec.ts单元测试,不用管它。

Nestjs的控制器Controller

@Controller() 装饰器,这是定义基本控制器所必需的。该装饰器可以传入一个路径参数,作为访问这个控制器的主路径(不传则表示默认路径)

请求对象

处理程序通常要访问客户端请求的详细信息。通过将 @Req() 装饰器添加到处理程序的签名来指示 Nest 注入它来访问请求对象。

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

@Controller('user')
export class UserController {
    @Get()
    getHello(@Req() request: Request): string {
        console.log(request);
        return 'Hello Nest.js!';
    }
}

请求对象表示 HTTP 请求,并具有请求查询字符串、参数、HTTP 标头和正文的属性等。在大多数情况下,没有必要手动获取这些属性。我们可以使用开箱即用的专用装饰器,例如 @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

资源

Nest 为所有标准的 HTTP 方法提供装饰器:@Get()、@Post()、@Put()、@Delete()、@Patch()、@Options() 和 @Head()。此外,@All() 定义了一个端点来处理所有这些。

ts
import { Controller, Delete, Get, Patch, Post, Put } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
    constructor(private readonly appService: AppService) {}

    // 匹配到 get 请求 http://localhost:3000
    @Get()
    getHello(): string {
        return this.appService.getHello();
    }

    // 匹配到 get 请求 http://localhost:3000/list
    @Get('/list')
    getHelloList(): string {
        return '这是list页面';
    }

    // 匹配到 post 请求 http://localhost:3000/list
    @Post('/list')
    create(): string {
        return 'post请求页面';
    }

    // 匹配到 put 请求 http://localhost:3000/list
    @Put('/list')
    update(): string {
        return 'put请求页面';
    }

    // 匹配到 delete 请求 http://localhost:3000/list
    @Delete('/list')
    delete(): string {
        return 'delete请求页面';
    }

    // 匹配到 patch 请求 http://localhost:3000/list
    @Patch('/list')
    patch(): string {
        return 'patch请求页面';
    }
}

路由参数

当接受动态数据作为请求的一部分时(例如,GET /cats/1 获取 ID 为 1 的 cat),具有静态路径的路由将不起作用。为了定义带参数的路由,在路由的路径中添加路由参数标记,以捕获请求 URL 中该位置的动态值。使用 @Param() 装饰器访问以这种方式声明的路由参数,应将其添加到方法签名中。

Param参数

ts
@Get(':id')
	// 请注意,在params方式获取参数中,必须是@Param(路径参数的名称,需要和:id这个地方保持一致),id:string这部分名称可以随意
  getUserInfoByParamId(@Param('id') id: string) {
    console.log(id, 'id');
    return 'getUserInfoByParamId';
 }

Query参数

ts
 @Get('/user')
 // 请注意:在query方式获取参数中,@Query('id') id: string和@Query() id: string的区别如下:
 // @Query() params: any获取的是一个获取所有query参数的解析对象,如{ a: '1', b: '2', c: '3' }
 // @Query('id') id: string获取的是query参数中具体的id这个参数的值
 // 如下:如果请求的路径是/xxx?a=1&b=2&c=3
 getUserInfoByQueryId(@Query() params: any, @Query('a') a: string) {
    console.log(params, 'params'); // { a: '1', b: '2', c: '3' }
    console.log(a, 'a') // 1
    return 'getUserInfoByQueryId';
 }

请求负载

我们之前的 POST 路由处理程序不接受任何客户端参数。遇到这种问题怎么办呢?我们可以使用 @Body() 装饰器来解决。

但首先我们需要确定 DTO(数据传输对象)架构。DTO 是定义数据如何通过网络发送的对象。我们可以通过使用 TypeScript 接口或简单的类来确定 DTO 模式。下面我们来创建一个 CreateCatDto 类:

ts
// create-cat.dto.ts
export class CreateCatDto {
    name: string;
    age: number;
    breed: string;
}

此后,我们可以在 demoController 中使用新创建的 DTO

ts
// demo.controller.ts
import { Body, Controller, Post } from '@nestjs/common';
import { DemoService } from './demo.service';
import { CreateCatDto } from './dto/create-cat.dto';

@Controller('demo')
export class DemoController {
  constructor(private readonly demoService: DemoService) {}

  @Post('/createUser')
  createUser(@Body() createCatDto: CreateCatDto) {
    console.log(createCatDto, 'createCatDto');
    return 'createCatDto';
  }
}

Nestjs的模块Module

模块是用 @Module() 装饰器注释的类。@Module() 装饰器提供 Nest 用于组织应用结构的元数据。至少有一个模块,即根模块。根模块是 Nest 用于构建应用图的起点 - Nest 用于解析模块和提供器关系及依赖的内部数据结构。

@Module() 装饰器采用单个对象,其属性描述模块:

字段功能
providers将由 Nest 注入器实例化并且至少可以在该模块中共享的提供程序
controllers此模块中定义的必须实例化的控制器集
imports导出此模块所需的提供程序的导入模块列表
exports这个模块提供的 providers 的子集应该在导入这个模块的其他模块中可用。你可以使用提供器本身或仅使用其令牌(provide 值)

输入 nest g resource user 生成一个基础的 CRUD 功能,现在目录结构为:

shell
src
 ├── user
 |    ├── dto
 |    |   ├── create-user.dto.ts
 |    |   └── update-user.dto.ts
 |    |
 |    ├── entities
 |    |   └── user.entity.ts
 |    |
 |    ├── user.controller.spec.ts
 |    ├── user.controller.ts
 |    ├── user.module.ts
 |    └── user.service.ts
 |
 ├── app.module.ts