返回文章列表

【nest】1 起步


这篇文章基于nest.js 10.0 版本,简单介绍了如何从零开始创建一个nest项目,以及nest常见的概念,
controller/service/module/interceptor/pipe/guard/middleware等等。

npm i -g @nestjs/cli

nest new project-name

//生成controller
nest g controller name

//生成service
nest g service name

//生成模块
nest g module name

//生成crud
nest g resource name

controller

controller 用来处理http路由,复杂逻辑传递给 service

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

@Controller("cat") // prefix
export class CatController {
  @Get() // path
  // 参数可以拿到express的Request对象
  findAll(@Req() request: Request): string {
    // 函数名、没意义
    return "This action returns all cats"; //标准模式下:基本类型返回值、对象类型自动序列化成 json
  }
}

service

service负责业务模块应用逻辑。

controller的构造函数里可以注入service,注入后即可通过this.catsService调用方法。

@Controller("cats")
export class CatsController {
  //注入service
  constructor(private catsService: CatsService) {}
}

尝试使用 fastify 和版本控制

import { NestFactory } from "@nestjs/core";
import { VersioningType } from "@nestjs/common";
import { AppModule } from "./app.module";
import {
  FastifyAdapter,
  NestFastifyApplication,
} from "@nestjs/platform-fastify";

async function bootstrap() {
  const app = await NestFactory.create<NestFastifyApplication>(
    AppModule,
    new FastifyAdapter()
  );

  app.enableVersioning({
    type: VersioningType.URI,
  });

  await app.listen(3000);
}
bootstrap();

为某个 api 添加版本控制

通过@Version装饰器为 api 添加版本号

@Version('1')
  @Get()
  async findAll(@Query() query: ListAllEntities) {
    return this.catService.findAll(query);
  }

我当时踩了一个坑,添加完版本号后访问http://localhost:3000/V1/cat是 404,是自己蠢了,路由区分大小写。

为某个 Controller 添加版本控制

@Controller({
  path: "cat",
  version: "1",
})
export class CatController {
  //some code
}

为整个 app 添加版本控制

app.enableVersioning({
  type: VersioningType.URI,
  defaultVersion: "1",
});

添加全局中间件

为 api 返回结果提供统一格式。

忽略掉乱七八糟的类型标注,其实这个 class 本质上就是一个简单的拦截器。

next.handle.pipe 暂时不理解。

// common/interceptors/transform.interceptor.ts
// 全局中间件

import {
  CallHandler,
  NestInterceptor,
  ExecutionContext,
  Injectable,
} from "@nestjs/common";
import { Observable } from "rxjs";
import { map } from "rxjs";

@Injectable()
export class TransformInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    return next.handle().pipe(map((data) => ({ data, message: "success" })));
  }
}

统一返回格式后,再基于拦截器为 app 添加全局异常拦截。

// common/exceptions/base.exception.filter.ts
// 全局异常拦截
// common/exceptions/http.exception.filter.ts
// 处理http异常

基于 vscode 调试

点 vscode 的 debug,创建配置文件。
删除默认的配置项,点击右下角Add Configuration,输入via npm,选择备选项,即可添加如下配置。

via npm是指通过 npm 启动调试。

start:debugpackage.json 中定义的脚本。

runtimeVersion 是 node 的版本,vscode 会基于 nvm 切换 node 版本。

internalConsoleOptions 是 vscode 的配置,neverOpen 表示不打开内部控制台。

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Launch via NPM",
      "request": "launch",
      "runtimeArgs": ["run-script", "start:debug"],
      "runtimeExecutable": "npm",
      "runtimeVersion": "20.17.0",
      "internalConsoleOptions": "neverOpen",
      "skipFiles": ["<node_internals>/**"],
      "type": "node"
    }
  ]
}

创建好配置文件后,无需再使用命令行启动调试,直接点 vscode 的 debug 按钮即可。

基于chrome调试

有时需要基于线上环境调试线上问题,可以使用chrome调试。

nest 提供了 start:debug 脚本,本质是开启inspect模式

随后我们可以通过浏览器访问chrome://inspect,发现 remote target 中有一个 nest 的 app,点击inspect,即可调起devtool进行调试。

开始时的一些坑

  • 路由区分大小写
  • 直接返回字符串导致前端报错 (无法解析 JSON)
  • controller 里的函数忘记 return 导致前端收到的响应是空白的
  • 在 service 函数里试图在 setTimeout 里返回响应模拟延迟