NodeJS-NestJS基础

485 阅读16分钟

NodeJS-NestJS基础

本文介绍 NestJS 框架相关的基础知识:NestJS框架介绍、环境搭建、MVC框架解析、模块Module、控制器Controller、服务Service、中间件Middleware、守卫Guard、管道Pipe等

供自己以后查漏补缺,也欢迎同道朋友交流学习。

引言

最近跟着满神学完了 NestJS 框架,也想记录下自己的学习过程。所以本文主要介绍 NestJS 框架相关的基础知识。

首先说下为什么学 NestJS 的原因,国内主流的一些 Node 框架还是 Express 或者 Koa,如果是企业级一般用 Egg。我选择 NestJS 是因为看到很多 AI 公司及外企的招聘 JD 都在用 NestJS,想着学一学对未来找工作更好。而且 NestJS 框架的底层默认是 Express,也支持 Fastify,学习成本也不高。

后来在 B 站找了学习视频和课程,接触到了 NestJS,发现它面向对象编程语法风格我非常喜欢,完全支持 TypeScript,中间件、依赖注入、模块化开发。

如果完全不了解 NodeJs,那下面的介绍会比较难上手,建议阅读下 NodeJS-基础学习

NestJS 框架介绍

NestJS 是一个用于构建高效、可扩展的 Node.js 服务器端应用程序的框架。它利用 TypeScript 来开发强类型、可扩展的应用程序。NestJS 深受 Angular 框架的启发,因此它的架构、模块化和依赖注入系统与 Angular 有许多相似之处。以下是 NestJS 的一些核心特性和概念:

  1. 依赖注入(DI):使用了一个强大的依赖注入系统,这是控制反转(IoC)容器的一个实现。依赖注入允许你将服务(例如数据库连接工具库等)注入到你的控制器、守卫、拦截器和服务中。

  2. 控制器:控制器处理 HTTP 请求和响应。它们通常用来定义路由和处理逻辑

  3. 服务:服务是应用程序的业务逻辑层,通常用于封装和重用逻辑,可以被控制器或其他服务调用。

  4. 守卫(Guards):守卫是特殊的类,可以用来预处理请求,例如身份验证授权

  5. 拦截器(Interceptors):拦截器用于拦截处理流程,可以在调用控制器之前或之后执行代码,例如日志记录错误处理

  6. 装饰器:广泛使用 JS 的装饰器,它被用于类和方法上,提供了一种强大的方式来添加额外信息行为

  7. 中间件:支持 ExpressFastify 等 HTTP 平台的中间件,允许你在应用程序中使用现有的中间件

  8. 插件和钩子:提供了生命周期钩子,允许你在应用程序的不同阶段执行代码。

  9. 微服务支持:支持构建微服务架构,提供了与消息传递系统(如 MQTTWebSockets)集成的工具。

  10. CQRS 和事件源:支持命令查询责任分离(CQRS)和事件源模式,这对于构建复杂的业务逻辑和数据一致性非常有用。

  11. 开箱即用:内置了许多开箱即用的解决方案,如数据库访问层文件上传处理缓存等。

NestJS 的设计理念是提供一个完整的解决方案,让开发者可以专注于构建业务逻辑,而不是花时间在底层架构上。

环境搭建

Node 和 Npm 环境安装

对于 NodeJsNpm 的安装,我不多做介绍,可以参考以下链接:

也可以看我之前写的NodeJS-基础学习

安装 NestJS CLI 工具

使用 CLI 工具(@nestjs/cli)快速创建新项目。

## 安装全局 NestJS CLI 工具
npm i -g @nestjs/cli

## 安装你的项目
nest new project-name

项目结构

默认生成的项目结构如下:

.
├── README.md // 项目说明
├── nest-cli.json // nest 命令文件,用于构建项目。
├── package-lock.json
├── package.json // 项目依赖包
├── src
│   ├── app.controller.spec.ts // 针对控制器的单元测试。
│   ├── app.controller.ts // 带有单个路由的基本控制器。
│   ├── app.module.ts // 应用程序的根模块(root module)。
│   ├── app.service.ts // 具有单一方法的基本服务(service)。
│   └── main.ts // 应用程序的入口文件,它使用核心函数 NestFactory 来创建 Nest 应用程序的实例。
├── test // 测试文件
│   ├── app.e2e-spec.ts
│   └── jest-e2e.json
├── tsconfig.build.json // tsconfig 文件,用于构建项目。
└── tsconfig.json

项目运行

下面命令将使用 HTTP 服务器启动应用程序,以侦听 src/main.ts 文件中所定义的端口。应用程序运行后,打开浏览器并访问 http://localhost:3000/ 地址,将看到类似 Hello World! 的信息。

npm run start

MVC经典架构解析

NestJS 中,app.controller.tsapp.module.tsapp.service.ts是三个基础且关键的文件,它们分别代表了控制器(Controller)、模块(Module)和服务(Service)的概念。这些文件共同协作,构成了NestJS应用的基础结构。这也是经典的MVC架构,下面我们逐一解析他们的作用。

app.controller.ts

控制器是处理传入请求返回响应的部分。它通常包含了一组路由处理器(路由装饰器如@Get(), @Post(), @Put(), @Delete()等),这些处理器将特定的请求映射到处理函数上。

import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';

// 定义为一个控制器
@Controller()
export class AppController {
  // 构造函数:注入 appService
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    // get 请求/返回 appService 的 getHello 方法
    return this.appService.getHello();
  }
}

AppController 类通过 @Controller() 装饰器定义为一个控制器,并且它依赖于 AppService 服务(通过构造函数注入)。@Get() 装饰器将 getHello 方法映射为 GET 请求的处理器,该方法调用了 AppServicegetHello 方法来获取响应字符串。

app.module.ts

模块是 NestJS 中用于封装和组织相关控制器服务、提供者( providers,如服务)和导入( imports,即其他模块)的容器。

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

// 通过@Module()装饰器定义为一个模块
@Module({
  imports: [], // 其他模块
  controllers: [AppController], // 控制器
  providers: [AppService], // 提供者,如服务
})
export class AppModule {}

AppModule 类通过 @Module() 装饰器定义为一个模块。它指定了当前模块包含的控制器( controllers 数组中的AppController)和提供者( providers 数组中的 AppService)。由于这是一个根模块,所以 imports 数组是空的。

app.service.ts

服务是 NestJS 中用于封装业务逻辑的部分。它们可以被注入到控制器或其他服务中,以便在多个地方重用逻辑。

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

// 定义为一个可注入的服务
@Injectable()
export class AppService {
  // 一般,定义数据库增删改查的方法
  getHello(): string {
    return 'Hello World!';
  }
}

AppService 类通过 @Injectable() 装饰器定义为一个可注入的服务。它提供了一个 getHello 方法,该方法返回一个简单的字符串“ Hello World! ”。这个服务可以在控制器中被注入并调用,以返回响应给客户端。

基本概念

模块(Modules)

通过上面的 app.module.ts,我们可以知道 Modules 是用于封装和组织相关importscontrollersproviders的容器。这个文件就是相当于前端的某个页面模块容器。

每个模块都可以定义以下部分:

  • controllers:处理传入请求并返回响应的组件。
  • providers:封装业务逻辑和数据的组件,通常是服务。
  • imports:当前模块需要依赖的其他模块列表。
  • exports:当前模块希望导出以便其他模块使用的提供者(服务、组件等)列表。

Modules示例

假设我们需要做一个用户管理的功能,我们可以创建一个名为 UserModule 的特性模块。

// User.module.ts
import { Module } from '@nestjs/common';
import { UserController } from './User.controller';
import { UserService } from './User.service';

@Module({
  controllers: [UserController],
  providers: [UserService],
  exports: [UserService], // 可以不写,如果其他模块需要 UserService,则导出它
})
export class UserModule {}

AppModule 中可以导入 UserModule,在整个应用程序中被访问和使用。

控制器(Controllers)

控制器的作用是如何定义路由和处理请求。控制器负责将请求路由到相应的处理函数,并可能调用服务(Services)来执行实际的业务逻辑。

控制器的基本概念

  • 路由:控制器通过装饰器(如@Get(), @Post(), @Put(), @Delete()等)将特定的HTTP请求方法映射到处理函数上。这些装饰器定义了请求的 URL 路径、请求方法以及任何请求参数。
  • 动作:控制器中的处理函数被称为动作。当请求与路由匹配时,相应的动作将被调用,并可以执行诸如验证请求调用服务返回响应等操作。
  • 响应:动作可以返回一个、一个对象、一个 Promise、一个 Observable 或是一个流(Stream),NestJS 会自动将其序列化为 JSON(对于对象、Promise和Observable)并发送回客户端。
import { Controller, Get, Post, Body, Patch, Param, Delete, Query } from '@nestjs/common';
import { UserService } from './user.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';

@Controller('user')
export class UserController {
  // 依赖注入
  constructor(private readonly userService: UserService) {}

  @Post()
  create(@Body() createUserDto: CreateUserDto) {
    // 调用服务来创建用户
    return this.userService.create(createUserDto);
  }

  @Get()
  findAll(@Query() query: { name: string; page: number; pageSize: number }) {
    return this.userService.findAll(query);
  }

  // 其他动作...
}

此外,NestJS 支持 PromiseObservable,你可以在控制器的动作中执行异步操作,如数据库查询HTTP 请求。NestJS会自动等待 Promise 解析或 Observable 完成,并将结果返回给客户端。

服务(Services)

服务(Services)是封装了特定业务逻辑和数据的组件。它们通常用于处理应用程序中需要执行的任务,如数据访问验证转换等。服务通常不直接处理 HTTP 请求,而是由控制器(Controllers)调用以完成特定的业务操作。

可以使用@Injectable()装饰器定义一个类来创建服务:

import { Injectable } from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { InjectRepository } from '@nestjs/typeorm';
import { User } from './entities/user.entity';
import { Tags } from './entities/tags.entity';
import { Like, Repository } from 'typeorm';

@Injectable()
export class UserService {
  // 注入 userRepository 用户数据库
  constructor(
    @InjectRepository(User) private readonly userRepository: Repository<User>,
  ) {}

  // 创建用户
  create(createUserDto: CreateUserDto) {
    const data = new User();
    data.name = createUserDto.name;
    data.desc = createUserDto.desc;

    return this.userRepository.save(data);
  }

  // 查询所有
  async findAll(query: { name: string; page: number; pageSize: number }) {
    const data = await this.userRepository.find({
      where: {
        name: Like(`%${query.name}%`),
      },
      order: {
        id: 'DESC',
      },
      skip: (query.page - 1) * query.pageSize,
      take: query.pageSize,
    });

    const total = await this.userRepository.count({
      where: {
        name: Like(`%${query.name}%`),
      },
    });

    return {
      data,
      total,
    };
  }

  // ...其他方法
}

服务通常负责以下职责:

  • 数据访问:服务可以封装与数据库、文件系统或其他数据源交互的代码。
  • 业务逻辑:服务可以包含执行特定业务规则和操作的代码。
  • 转换和验证:服务可以对输入数据进行验证,并将内部数据转换为适合外部使用的格式。
  • 依赖管理:服务可以管理对其他服务的依赖,并将它们封装在单个接口中,以简化组件之间的交互。

依赖注入(DI)

依赖注入(Dependency Injection,简称 DI)是一种软件设计模式,它允许一个类(或对象)的依赖项在创建时或运行时被外部传入,而不是在类内部自行创建。

依赖注入的几种方式:

  • 构造函数注入:通过类的构造函数传入依赖项。
  • Setter方法注入:通过类的 setter 方法传入依赖项。
  • 接口注入:这种方式较少使用,主要通过接口来定义依赖项,并在实现类中注入这些依赖项。

装饰器(Decorators)

在 NestJS 大量使用的装饰器,如 @Controller, @Get, @Post 等,常见的装饰器类型包括:

  1. 类装饰器:用于类级别,可以修改类的行为或添加元数据。
  2. 方法装饰器:用于方法级别,可以修改方法的行为或添加元数据。
  3. 属性装饰器:用于类属性级别,可以修改属性的行为或添加元数据。
  4. 参数装饰器:用于方法参数级别,可以访问或修改方法参数的信息。
NestJS 中的核心装饰器
  • @Module():用于定义模块。
  • @Injectable():用于标记服务类,使其能够由依赖注入系统管理和注入。
  • @Controller():用于定义路由的基类,可以指定路由前缀。
  • @Get(), @Post(), @Put(), @Delete(), ...:这些装饰器用于定义路由处理器(Route Handlers),指定处理 HTTP 请求的方法(如 GETPOST 等)和路径。
  • @Inject()、InjectRepository():用于在构造函数中注入依赖项。虽然 @Injectable() 已经为服务类启用了依赖注入,但 @Inject() 允许你更具体地控制注入过程,特别是在处理非类依赖项时。
  • @UseGuards():用于在路由处理器或整个控制器上应用守卫(Guards)。守卫用于实现认证、授权等安全机制。
自定义装饰器

NestJS 也支持自定义装饰器,允许你根据需要定义自己的装饰器逻辑。自定义装饰器通常用于添加自定义元数据或修改类的行为。

const Log = (target: Object, key: string | symbol, descriptor: TypedPropertyDescriptor<any>) => {
  const originalMethod = descriptor.value;

  descriptor.value = function(...args: any[]): any {
    console.log(`Calling ${key.toString()} with args`, args);
    const result = originalMethod.apply(this, args);
    console.log(`Called ${key.toString()}, result is ${result}`);
    return result;
  };

  return descriptor;
};

@Log
methodToLog() {
  // 方法体
}

NestJS 中,装饰器是实现模块化、依赖注入和面向切面编程等关键概念的重要工具。它们极大地提高了代码的可读性、可维护性和可扩展性。

进阶特性

中间件(Middleware)

中间件主要用于全局请求处理,可以用于日志记录错误处理身份验证等功能。

middleware

NestJS 中,中间件分为两种类型:

  1. 全局中间件:可以在整个应用程序范围内生效。

  2. 局部中间件:仅在特定的路由或控制器中生效。

创建和使用中间件:

首先,我们需要创建一个中间件类。中间件类需要实现 NestMiddleware 接口,并且必须有一个 use 方法来处理 HTTP 请求和响应。

// 创建中间件
import { NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';

export class LoggerMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    console.log(`Request received at ${req.url}`);
    next(); // 调用 next() 来传递控制权给下一个中间件或路由处理器
  }
}

要将中间件应用于整个应用程序,需要在主模块(通常是 AppModule)中注册中间件。

import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { LoggerMiddleware } from './middlewares/logger.middleware';

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoggerMiddleware)
      .forRoutes('*'); // 应用于所有路由
  }
}

如果只想在特定的路由或控制器中使用中间件,可以在路由定义时指定。

import { Controller, Get, UseMiddleware } from '@nestjs/common';
import { AppService } from './app.service';
import { LoggerMiddleware } from './middlewares/logger.middleware';

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

  @Get()
  @UseMiddleware(LoggerMiddleware) // 应用于特定的路由
  getHello(): string {
    return this.appService.getHello();
  }
}

NestJS 还提供了一些装饰器来更方便地应用中间件:

  • @UseInterceptors(): 用于应用拦截器。
  • @UseGuards(): 用于应用守卫。
  • @UsePipes(): 用于应用管道。

虽然这些装饰器主要用于其他目的,但在某些情况下也可以与中间件一起使用来增强功能。

管道(Pipes)

管道一般用于请求数据的转换验证预处理

pipes

创建管道

要创建一个管道,需要定义一个类,并实现 PipeTransform 接口。接口有两个方法需要实现:transformparsetransform 方法用于对数据进行转换处理,而 parse 方法用于反向操作

下面是一个简单的管道示例,用于验证和转换 userId 参数:

// ./pipes/parse-user-id.pipe
import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';

@Injectable()
export class ParseUserIdPipe implements PipeTransform<string, number> {
  transform(value: string, metadata: ArgumentMetadata): number {
    const val = parseInt(value, 10);
    if (isNaN(val)) {
      throw new BadRequestException('Validation failed');
    }
    return val;
  }
}
  • PipeTransform<string, number> 指定了输入类型为 string,输出类型为 number
  • transform 方法将字符串转换为数字,并检查转换后的值是否为 NaN(非数字)。

使用管道

管道可以通过装饰器应用到控制器的方法参数上,或者在全局范围内应用。

import { Controller, Get, Param, UsePipes } from '@nestjs/common';
import { ParseUserIdPipe } from './pipes/parse-user-id.pipe';

@Controller('users')
export class UserController {
  // 使用 @UsePipes 装饰器来应用管道
  @Get(':id')
  @UsePipes(ParseUserIdPipe)
  getUser(@Param('id') id: number) {
    // id 已经被转换为数字类型
    console.log(id);
    return `User with ID: ${id}`;
  }
}

还可以在全局范围内应用管道,这样就不需要在每个控制器方法中单独定义。

import { NestFactory } from '@nestjs/core';
import { ValidationPipe } from '@nestjs/common';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(new ValidationPipe());
  await app.listen(3000);
}
bootstrap();

NestJS 提供了一些内置的管道,可以开箱即用:

  • ValidationPipe:可以确保传入的数据符合一定的验证规则,并且可以将数据转换成期望的格式。
  • ParseIntPipe:将数据转换为整数。
  • ParseFloatPipe:将数据转换为浮点数。
  • ParseBoolPipe:将数据转换为布尔值。
  • ParseArrayPipe:将数据转换为数组。
  • ParseEnumPipe:将数据转换为枚举。
  • ParseUUIDPipe:将数据转换为UUID。
  • DefaultValuePipe:用于在传入的参数为空或未定义时提供一个默认值。

守卫(Guards)

守卫(Guards)是一种特殊的机制,用于保护路由和控制器方法,确保只有在满足特定条件时才允许执行这些方法。

Guards

守卫主要用于以下几个方面:

  1. 身份验证:确保用户已登录或拥有执行某些操作所需的权限。

  2. 授权:确保用户具有访问资源的权限。

  3. 条件路由:根据某些条件决定是否应该执行某个路由处理程序。

  4. 错误处理:在执行路由处理程序之前捕获错误。

创建守卫

要创建一个守卫,需要定义一个类,并实现 CanActivate 接口。

// guards/auth.guard
@@filename(auth.guard)
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Observable } from 'rxjs';

@Injectable()
export class AuthGuard implements CanActivate {
  // 这个接口定义了一个 `canActivate` 方法,该方法返回一个布尔值或一个返回布尔值的 `Promise`,表示是否允许请求继续。
  canActivate(context: ExecutionContext): boolean | Promise<boolean> | Observable<boolean> {
    // 获取请求对象
    const request = context.switchToHttp().getRequest();
    // 检查用户是否已登录
    return request.isAuthenticated();
  }
}

使用守卫

守卫可以通过装饰器应用到控制器或特定方法上

import { Controller, Get, UseGuards } from '@nestjs/common';
import { AuthGuard } from './guards/auth.guard';

@Controller('users')
@UseGuards(AuthGuard) // 应用于整个控制器
export class UsersController {
  @Get()
  findAll() {
    return 'List of users';
  }

  @Get(':id')
  @UseGuards(AuthGuard) // 应用于特定方法
  findOne() {
    return 'Details of user';
  }
}

NestJS 提供了几种内置的 Guard

  • AuthGuard: 用于身份验证。它检查请求是否包含有效的认证凭据,并在验证失败时抛出异常。
  • RolesGuard: 用于基于角色访问控制。它确保只有具有特定角色的用户才能访问特定的路由。
  • PermissionGuard: 用于基于权限的访问控制。它确保用户具有执行特定操作的权限。
  • ThrottlerGuard: 用于速率限制。它限制用户在给定时间内可以发起的请求数量。
  • WsGuard: 用于 WebSocket 连接的守卫。它允许你在 WebSocket 连接建立之前执行一些逻辑。

拦截器(Interceptors)

拦截器(Interceptors)的作用是修改请求或响应。它们非常适合用于日志记录性能监控数据转换错误处理缓存处理等场景。

Interceptor

创建拦截器

要创建一个拦截器,您需要定义一个类,并实现 Interceptor 接口。这个接口定义了一个 intercept 方法,该方法接收 ExecutionContextCallHandler 作为参数。

// interceptors/logging.interceptor
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';

@Injectable()
export class LoggingInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    console.log('Before...');
    const now = Date.now();

    // 调用 next() 来执行后续的处理
    return next.handle().pipe(
      tap(() => console.log(`After... ${Date.now() - now}ms`)),
    );
  }
}

使用拦截器

拦截器可以通过装饰器应用到控制器或特定的方法上。

import { Controller, Get, UseInterceptors } from '@nestjs/common';
import { LoggingInterceptor } from './interceptors/logging.interceptor';

@Controller('cats')
@UseInterceptors(LoggingInterceptor) // 应用于整个控制器
export class CatsController {
  @Get(':id')
  @UseInterceptors(LoggingInterceptor) // 应用于特定方法
  findOne() {
    return 'Details of cat';
  }
}

还可以在全局范围内应用拦截器,这样就不需要在每个控制器方法中单独定义。

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { PerformanceInterceptor } from './interceptors/performance.interceptor';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalInterceptors(new PerformanceInterceptor());
  await app.listen(3000);
}
bootstrap();

NestJS 提供了一些内置的拦截器:

  • ClassSerializerInterceptor: 用于序列化和反序列化对象,确保响应对象只包含预期的属性。
  • TransformInterceptor:用于转换传入的数据,可以用于自定义数据转换逻辑。
  • SerializeInterceptor:用于序列化响应数据,可以用于确保响应数据符合一定的格式。
  • DeserializeInterceptor:用于反序列化请求数据,可以用于确保请求数据符合一定的格式。

异常过滤器(Exception Filters)

异常过滤器(Exception Filters)是一种用于处理未捕获的异常的机制。它们可以在应用程序抛出异常时介入,并提供自定义的错误处理逻辑。可以优雅地处理错误,统一错误响应格式,并执行额外的日志记录其他操作

Exception Filters

创建异常过滤器

要创建一个异常过滤器,需要定义一个类,并实现 ExceptionFilter 接口。这个接口定义了一个 catch 方法,该方法接收异常实例、上下文和调用处理器作为参数。

import { ExceptionFilter, Catch, ArgumentsHost, HttpException, HttpStatus } from '@nestjs/common';
import { Request, Response } from 'express';

@Catch() // 标记为全局异常过滤器
export class AllExceptionsFilter implements ExceptionFilter {
  // 方法用于处理异常,并返回一个标准的 JSON 格式的错误响应。
  catch(exception: unknown, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();

    const status =
      exception instanceof HttpException
        ? exception.getStatus()
        : HttpStatus.INTERNAL_SERVER_ERROR;

    response.status(status).json({
      statusCode: status,
      timestamp: new Date().toISOString(),
      path: request.url,
      message: exception instanceof HttpException ? exception.message : 'Internal server error',
    });
  }
}

异常过滤器可以通过装饰器应用到控制器或特定的方法上,也可以全局应用。

import { Controller, Get, UseFilters } from '@nestjs/common';
import { AllExceptionsFilter } from './filters/all-exceptions.filter';

@Controller('cats')
@UseFilters(AllExceptionsFilter) // 应用于整个控制器
export class CatsController {
  @Get()
  findAll() {
    // 抛出异常
    throw new Error('An error occurred');
  }
}

全局应用异常过滤器

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { AllExceptionsFilter } from './filters/all-exceptions.filter';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  // 全局应用异常过滤器
  app.useGlobalFilters(new AllExceptionsFilter());
  await app.listen(3000);
}
bootstrap();

CLI快捷命令

NestJS 提供了许多实用的 CLI(命令行接口)命令来简化项目的设置、管理和开发过程。以下是一些常用的快捷命令

命令别名缩写描述
nest generate resource RESOURCE-NAMEnest g res RESOURCE-NAME将创建一个新的资源包含CRUD及控制器、服务、模块
nest generate module MODULE-NAMEnest g mo MODULE-NAME将创建一个新的模块(目录)以及相关的 module.ts 文件
nest generate controller CONTROLLER-NAMEnest g co CONTROLLER-NAME生成控制器,可以使用 --no-spec 标志来避免生成测试文件。这个命令会创建一个新的控制器文件和基本的路由处理方法。
nest generate service SERVICE-NAMEnest g s SERVICE-NAME生成一个新的服务类,服务通常用于封装应用逻辑。
nest generate guard GUARD-NAMEnest g gu GUARD-NAME创建用于定义应用层的安全规则的守卫
nest generate interceptor INTERCEPTOR-NAMEnest g in INTERCEPTOR-NAME拦截器可以修改方法执行的行为,如响应、请求处理前后执行特定的逻辑。
nest generate filter FILTER-NAMEnest g f FILTER-NAME过滤器允许你处理异常或请求,以及发送自定义的响应给客户端。
nest generate pipe PIPE-NAMEnest g pi PIPE-NAME管道是处理数据的另一种方式,可以自动转换输入到路由处理器或从路由处理器转换输出。

实战案例

后续写一个案例

参考文档