小白从0开始——NestJS官网文档精读:异常过滤器

抛出标准异常

内置的 HttpException

HttpException 构造函数所需的三个参数:

  1. 必需,response 参数定义 JSON 响应主体。它可以是 stringobject

默认情况下,JSON 响应主体对象object包含两个属性:

  • statusCode:默认为 status 参数中提供的 HTTP 状态代码

  • message:基于 status 的 HTTP 错误的简短描述

response可传递一个对象object:覆盖整个 JSON 响应主体
response 参数为一个字符串string:仅覆盖 JSON 响应正文的消息部分

response 参数中传递一个对象object:覆盖整个 JSON 响应主体

  1. 必需,status 参数定义了 HTTP 状态代码

使用从 @nestjs/common 导入的 HttpStatus 枚举

  1. options - 可用于提供错误 cause。此 cause 对象未序列化到响应对象中,但它可用于记录目的,提供有关导致 HttpException 被抛出的内部错误的有价值信息
typescript 复制代码
@Get()
async findAll() {
  try {
    await this.service.findAll()
  } catch (error) { 
    throw new HttpException({
    //第一个参数`response`传递一个对象`object`:覆盖整个 JSON 响应主体。
    //不再是默认的statusCode和message
      status: HttpStatus.FORBIDDEN,
      error: 'This is a custom message',
    }, HttpStatus.FORBIDDEN, {
      cause: error
    });
  }
}

通常来说,当你抛出一个标准的HttpException,NestJS会默认返回一个包含statusCode和message属性的JSON响应体。但你可以通过传递一个自定义对象作为HttpException的第一个参数来覆盖这个默认响应体,这个对象中可以包含任何你想要的属性。

自定义异常

自定义异常继承自 HttpException 基类。通过这种方法,Nest 将识别你的异常,并自动处理错误响应。

scala 复制代码
import { HttpException, HttpStatus } from '@nestjs/common';

export enum CustomErrorCode {
  USER_NOTEXIST = 10002, // 用户不存在
  USER_EXIST = 10003, //用户已存在
}
export class CustomException extends HttpException {
  private errorMessage: string;
  private errorCode: CustomErrorCode;

  constructor(
    errorMessage: string,
    errorCode: CustomErrorCode,
    statusCode: HttpStatus = HttpStatus.OK,
  ) {
    super(errorMessage, statusCode);
    this.errorMessage = errorMessage;
    this.errorCode = errorCode;
  }

  getErrorCode(): CustomErrorCode {
    return this.errorCode;
  }

  getErrorMessage(): string {
    return this.errorMessage;
  }
}

当你在 CustomException 类的构造函数中调用 super(errorMessage, statusCode),你实际上是在将 errorMessage 作为响应体和 statusCode 作为HTTP状态码传递给 HttpException 类的构造函数。第一节中HttpException 类的第一第二个参数

HttpException 类构造函数的签名大概是这样的

typescript 复制代码
constructor(response: string | object, status: number,options?:object) {
  // ...
}

拓展super

super关键字用于调用一个类的父类构造函数或方法,生成一个父类的实例即子类。它常在继承场景中使用,当子类需要访问或者调用父类的构造函数、方法时使用。

在子类中调用super时,你实际上是在调用父类的构造函数。这意味着任何你传递给super的参数都是用来初始化父类的实例的。HttpException的上下文中,super(errorMessage, statusCode)会将errorMessage作为响应体(response body)和statusCode作为HTTP状态码传递给HttpException构造函数。

在子类构造函数中,super 必须在使用 this 访问属性或调用方法之前被调用,因为在JavaScript类的上下文中,this 关键字在 super 被成功调用前是不能使用的。这是因为父类构造函数负责创建类的实例,在父类构造函数执行完毕之前,子类的实例被认为是不完整的。

CustomException 的构造函数里,调用了 super 之后,新的 CustomException 实例就具备了 HttpException 的所有行为,并且还可以进一步添加其特定的属性(errorMessageerrorCode)和方法(getErrorCodegetErrorMessage)。这样做的好处是你可以创建自定义的异常类型,它们在继承了基础异常功能的同时,还可以添加额外的信息和行为。

typescript 复制代码
import { HttpException, HttpStatus } from '@nestjs/common';

export class CustomException extends HttpException {
  private errorMessage: string;

  constructor(errorMessage: string, statusCode: HttpStatus) {
    //调用super,传入父类构造函数必需的参数生成子类
    super(errorMessage, statusCode);
    //添加子类自己的属性,在这里和父类的第一个参数response里的message相同
    this.errorMessage = errorMessage;
  }
//添加子类自己的方法
  getErrorMessage(): string {
    return this.errorMessage;
  }

// 获取父类中的方法或者属性HttpException的response
  getHttpExceptionRes() {
    return this.getResponse();
  }
}

// 使用示例
const customException = new CustomException('An error occurred', HttpStatus.BAD_REQUEST);
console.log(customException.getErrorMessage()); // 输出: An error occurred
console.log(customException.getHttpExceptionRes()); // 输出:  An error occurred

异常过滤器

src/http-exception.filter.ts

typescript 复制代码
import { ExceptionFilter, Catch, ArgumentsHost, HttpException,NotFoundException } from '@nestjs/common';
import { Request, Response } from 'express';

//`@Catch()` 装饰器可以采用单个参数或逗号分隔的列表。这使你可以一次为多种类型的异常设置过滤器。
@Catch(HttpException,NotFoundException)
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();
    const status = exception instanceof HttpException ? exception.getStatus() : 500; // 获取异常的状态码
    
    // 判断是否为NotFoundException 
    if (exception instanceof NotFoundException) { 
        response.status(status).json({ 
            statusCode: status, 
            message: '资源未找到', // 自定义消息 
            timestamp: new Date().toISOString(), 
            path: request.url, 
        }); 
        return; 
    }
    
      //判断是否为自定义异常类
    if (exception instanceof CustomException) {
      response.status(status).json({
        statusCode: exception.getErrorCode(),// 使用自定义异常中的错误码
        message: exception.getErrorMessage(),// 使用自定义异常中的错误消息
        timestamp: new Date().toISOString(),
        path: request.url,
        test:'自定义业务异常:用户异常'
      });
      return;
    }

// 通用异常处理
    response
      .status(status)
      .json({
        statusCode: status,
        timestamp: new Date().toISOString(),
        path: request.url,
      });
  }
}

所有异常过滤器都应实现通用 ExceptionFilter<T> 接口。

警告 如果你使用 @nestjs/platform-fastify,则可以使用 response.send() 而不是 response.json()。不要忘记从 fastify 导入正确的类型。

解释:Express是默认的HTTP平台,但你可以选择使用Fastify。上述异常过滤器例子是为Express平台设计的。

适用于Fastify平台的例子:

typescript 复制代码
import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common';
import { FastifyReply } from 'fastify';

@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<FastifyReply>();
    const request = ctx.getRequest<Request>();
    const status = exception.getStatus();

    response
      .status(status)
      .send({
        statusCode: status,
        timestamp: new Date().toISOString(),
        path: request.url,
      });
  }
}

绑定过滤器

应用过滤器

  1. 通过直接实例化过滤器类
less 复制代码
Controller

@Post()
@UseFilters(new HttpExceptionFilter())
async create(@Body() createCatDto: CreateCatDto) {
  throw new ForbiddenException();
}

使用 new HttpExceptionFilter() 时,您为每个使用它的控制器或处理程序创建了一个新的过滤器实例。在这种情况下,每个 @Post() 装饰器的请求处理程序将拥有自己的 HttpExceptionFilter 实例。这意味着如果您在多个地方使用过滤器,将会创建多个相同的过滤器实例,从而增加了内存使用。

  1. 通过传递过滤器类本身
less 复制代码
Controller

@Post()
@UseFilters(HttpExceptionFilter)
async create(@Body() createCatDto: CreateCatDto) {
  throw new ForbiddenException();
}

直接传递类 HttpExceptionFilter 而不是它的实例时,NestJS的依赖注入系统将负责管理过滤器的实例化。这意味着NestJS可以在内部优化和重用过滤器的实例。在这种情况下,无论过滤器在多少个地方被使用,整个模块中都只有一个过滤器实例被创建和管理,这减少了内存使用。

尽可能使用类而不是实例来应用过滤器。它减少了内存使用量,因为 Nest 可以轻松地在整个模块中重用同一类的实例。

⭐️⭐️⭐️为什么类优于实例:

当您直接使用类(如 @UseFilters(HttpExceptionFilter))时,NestJS可以利用其内置的依赖注入(DI)系统来管理异常过滤器的生命周期。DI系统会在需要的时候创建过滤器的单例,并且在整个应用程序中重用这个单例。这增加了性能和资源的效率,因为:

  • 减少了内存的开销,因为不需要为每个控制器或每个请求处理程序创建单独的过滤器实例。
  • 允许NestJS的生命周期钩子(例如 onModuleInitonApplicationShutdown)在过滤器类上工作,这对于实现一些初始化和清理逻辑是有用的。
  • 便于在过滤器内部注入依赖项。使用DI系统,您可以在过滤器的构造函数中注入其他服务或提供者,而当您直接实例化一个过滤器时,这是不可能的。

综上所述,使用类来应用过滤器(@UseFilters(HttpExceptionFilter))而不是实例(@UseFilters(new HttpExceptionFilter()))是更好的做法,因为它能够提高性能并减少内存占用。这种实践符合NestJS推荐的最佳实践,能够让您的应用程序更加高效和可维护。

举例说明:👇🏻

typescript 复制代码
// some.service.ts
import { Injectable } from '@nestjs/common';

@Injectable()
export class SomeService {
  doSomething() {
    // ... 实现一些业务逻辑
  }
}

// http-exception.filter.ts
import { Catch, ExceptionFilter, HttpException, ArgumentsHost } from '@nestjs/common';
import { SomeService } from './some.service';

@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
    //DI系统可通过构造函数注入服务
  constructor(private readonly someService: SomeService) {}

  catch(exception: HttpException, host: ArgumentsHost) {
    // 使用注入的服务来执行一些操作
    this.someService.doSomething();
    
    // ... 其他异常处理逻辑
  }
}

// app.module.ts
import { Module } from '@nestjs/common';
import { SomeService } from './some.service';
import { APP_FILTER } from '@nestjs/core';

@Module({
  providers: [
    SomeService,
    {
      provide: APP_FILTER,
      useClass: HttpExceptionFilter,
    },
  ],
  // ... 其他模块配置
})
export class AppModule {}

在NestJS中,依赖注入(DI)系统允许你在类的构造函数中注入服务或提供者。

这意味着你可以在类中轻松获取其他服务的实例,而无需手动创建它们。这是通过在类构造函数的参数中使用装饰器(例如 @Inject())来完成的。

通过在HttpExceptionFilter的构造函数中声明SomeService类型的参数,并且由于SomeService被标记为@Injectable(),NestJS的DI系统将会自动为HttpExceptionFilter提供一个SomeService的实例。

然后,在HttpExceptionFiltercatch方法中,我们可以调用这个注入的服务的方法,例如this.someService.doSomething(),以便在处理异常时执行一些业务逻辑。

如果我们直接实例化HttpExceptionFilter,例如使用new HttpExceptionFilter(),我们就需要手动处理所有的依赖注入,这不仅增加了代码复杂性,而且破坏了NestJS依赖注入系统的封装性和自动管理能力。

最后,通过在AppModule中配置APP_FILTER提供者,我们告诉NestJS,HttpExceptionFilter应该被用作全局异常过滤器,这样它就会自动用于处理整个应用中的HTTP异常。因为它是通过NestJS的DI系统注册的,所以所有的依赖项------在这个例子中是SomeService------都会被自动注入到HttpExceptionFilter,提供了一个干净、可维护且易于测试的代码结构。

为什么如果我们直接实例化HttpExceptionFilter,例如使用new HttpExceptionFilter(),我们就需要手动处理所有的依赖注入

当你直接实例化HttpExceptionFilter时,例如使用new HttpExceptionFilter(),你绕过了NestJS的依赖注入(DI)系统。DI系统的一个关键特性是能够自动解析类的依赖关系并提供相应的服务实例。这意味着,当一个类通过构造函数请求依赖时,NestJS框架会自动创建这些依赖的实例并将它们注入到类中。

如果你选择手动实例化一个类,而不是通过DI系统:

ini 复制代码
const myFilter = new HttpExceptionFilter();

那么你也必须手动提供该类所有依赖的实例:

ini 复制代码
const someService = new SomeService();
const myFilter = new HttpExceptionFilter(someService);

这种方式有几个缺点:

  1. 增加了样板代码:每次使用过滤器时,都需要重复创建依赖的代码。
  2. 降低了可维护性 :如果HttpExceptionFilter依赖的服务有所更改或者需要额外的依赖,你必须找到所有手动创建该过滤器的地方并更新构造参数。
  3. 失去了依赖注入的好处:当依赖项通过DI系统提供时,依赖项可以配置为单例或请求范围,或者可以进行其他高级配置。手动实例化时,你需要自己处理这些问题。
  4. 使得代码难以测试:自动化测试时,DI系统可以轻松地用mock或stub替换真实的服务实例。如果依赖是手动注入的,这个过程就会变得复杂。
  5. 破坏了依赖的封装性:手动实例化迫使你关注过滤器依赖的具体实现,而这些通常应该是不可见的。它还暴露了应用程序的内部构造,这违反了面向对象设计的封装原则。

因此,推荐使用NestJS的DI系统来管理类的依赖关系,而不是手动实例化类。这样做可以保持代码的整洁、一致,同时保持高度的可维护性和可测试性。

总结:当通过装饰器(如@UseFilters())在控制器或路由处理级别应用过滤器时,你可以传入类而不是实例。这样做使得NestJS的依赖注入(DI)系统能够控制过滤器的实例化过程。DI系统会负责创建过滤器实例并解析其构造函数中的所有依赖项。这种方式的主要好处是可以在过滤器中利用NestJS的DI来注入其他服务或提供者。

应用全局过滤器

1. 在main.ts中通过app.useGlobalFilters绑定

csharp 复制代码
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalFilters(new HttpExceptionFilter());
  await app.listen(3000);
}
bootstrap();

缺点:不能注入依赖 从任何模块外部注册的全局过滤器(如上例中的 useGlobalFilters())不能注入依赖,因为这是在任何模块的上下文之外完成的。

通过app.useGlobalFilters()方法设置全局过滤器时,你需要提供过滤器的实例new HttpExceptionFilter()而不是类本身。

这是因为useGlobalFilters()方法在Nest应用的根级别调用,此时依赖注入容器还没有完全准备好或方法调用不通过DI系统。因此,NestJS无法自动为你提供过滤器的依赖项,所以你必须手动实例化过滤器,并且如果过滤器有依赖项,你需要手动处理这些依赖。

2. 使用依赖注入特性,在模块层面使用APP_FILTER标记来提供过滤器:

python 复制代码
import { Module } from '@nestjs/common';
import { APP_FILTER } from '@nestjs/core';

@Module({
  providers: [
    {
      provide: APP_FILTER,
      useClass: HttpExceptionFilter,
    },
  ],
})
export class AppModule {}

HttpExceptionFilter就可以享受到NestJS依赖注入系统的所有好处,包括自动实例化和构造函数依赖注入。

总之,app.useGlobalFilters()方法需要过滤器的实例是因为它在应用程序的根级别执行,此时不能通过NestJS的DI系统来自动解析和注入依赖项。为了在全局过滤器中使用依赖注入,推荐在模块级别使用APP_FILTER提供过滤器。

捕获一切

@Catch()参数列表为空,则捕获一切

typescript 复制代码
import { ExceptionFilter, Catch, ArgumentsHost } from '@nestjs/common';

@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
  catch(exception: unknown, host: ArgumentsHost) {
    // ...处理所有异常的逻辑
  }
}

警告⚠️: 如果你需要同时使用两种过滤器:一个针对特定类型的异常,一个捕获所有异常------那么它们的声明顺序变得很重要

先通用(兜底)过滤器AllExceptionsFilter -> 特定类型的过滤器HttpExceptionFilter

vbscript 复制代码
app.useGlobalFilters(new AllExceptionsFilter(), new HttpExceptionFilter());
typescript 复制代码
import { Module } from '@nestjs/common';
import { APP_FILTER } from '@nestjs/core';
import { AllExceptionsFilter } from './all-exceptions.filter';
import { HttpExceptionFilter } from './http-exception.filter';

@Module({
  providers: [
    {
      provide: APP_FILTER,
      useClass: AllExceptionsFilter,
      // 可选的:如果你想设置顺序,可以提供 'priority' 属性
      // priority: 1,
    },
    {
      provide: APP_FILTER,
      useClass: HttpExceptionFilter,
      // 可选的:如果你想设置顺序,可以提供 'priority' 属性
      // priority: 2,
    },
  ],
  // ...其他模块配置
})
export class AppModule {}

AllExceptionsFilter 将首先注册为全局过滤器,其次是 HttpExceptionFilter。NestJS会先使用HttpExceptionFilter尝试处理异常,如果HttpExceptionFilter没有捕获到异常(因为它可能只针对特定的HttpException),那么AllExceptionsFilter会接手处理剩余的所有异常

过滤器是唯一一个不按照全局第一顺序执行的组件。而是会从最低层次开始处理,也就是说先从任何路由绑定的过滤器开始,然后是控制器层,最后才是全局过滤器。注意,异常无法从过滤器传递到另一个过滤器;如果一个路由层过滤器捕捉到一个异常,一个控制器或者全局层面的过滤器就捕捉不到这个异常。如果要实现类似的效果可以在过滤器之间使用继承。

继承

AllExceptionsFilter如何继承和扩展 BaseExceptionFilter 的逻辑

定义一个过滤器👇🏻

scala 复制代码
import { Catch, ArgumentsHost } from '@nestjs/common';
import { BaseExceptionFilter } from '@nestjs/core';

@Catch()
export class AllExceptionsFilter extends BaseExceptionFilter {
  catch(exception: unknown, host: ArgumentsHost) {
      // 调用继承的 `catch()` 方法
    super.catch(exception, host);
  }
}

警告:扩展 BaseExceptionFilter 的方法范围和控制器范围的过滤器不应使用 new 实例化。相反,让框架自动实例化它们。

解释:

这个警告是关于NestJS异常过滤器的实例化方法的。在NestJS中,如果你创建了一个扩展了BaseExceptionFilter的自定义异常过滤器,你不应该手动使用new关键字来创建这个过滤器的实例。这是因为NestJS框架提供了依赖注入系统来处理服务和过滤器的实例化,它可以自动解析和注入依赖。

当你手动实例化一个过滤器时,这个过滤器的依赖不会被NestJS自动解析和注入,这可能会导致运行时错误,因为过滤器可能需要依赖于其他服务,而这些服务只有通过NestJS的依赖注入系统才能获得。

因此,如果你想让你的过滤器能够利用NestJS的依赖注入能力,你应该让NestJS来负责实例化过滤器。

如何使用过滤器👇🏻

1. 全局过滤器:因此,在模块层面使用APP_FILTER标记来提供过滤器✅

typescript 复制代码
// app.module.ts
import { Module } from '@nestjs/common';
import { APP_FILTER } from '@nestjs/core';
import { AllExceptionsFilter } from './all-exceptions.filter';

@Module({
  providers: [
    {
      provide: APP_FILTER,
      useClass: AllExceptionsFilter,
    },
  ],
})
export class AppModule {}

2. 控制器或路由处理程序级别的过滤器:你可以使用@UseFilters()装饰器并直接传入类(而不是实例)✅:

kotlin 复制代码
// your.controller.ts
import { Controller, UseFilters } from '@nestjs/common';
import { AllExceptionsFilter } from './all-exceptions.filter';

@Controller('your-route')
@UseFilters(AllExceptionsFilter)
export class YourController {
  // ...
}

⚠️ 什么级别的过滤器都不要使用new AllExceptionsFilter()来创建实例

全局过滤器AllExceptionsFilter可以扩展基本过滤器,如HttpAdapter

1. 在实例化自定义全局过滤器时注入 HttpAdapter 引用

csharp 复制代码
async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  const { httpAdapter } = app.get(HttpAdapterHost);
  app.useGlobalFilters(new AllExceptionsFilter(httpAdapter));

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

HttpAdapter 是 NestJS 在其底层抽象层中使用的一个接口,旨在提供一个不依赖于特定HTTP服务器实现(如Express或Fastify)的方式来处理HTTP请求和响应。这使得NestJS能够以一种与底层HTTP平台无关的方式工作,从而增加了框架的灵活性和可移植性。

HttpAdapterHost 是一个特殊的包装器服务,它提供了对当前应用程序使用的 HttpAdapter 的访问。通过从 HttpAdapterHost 获取 httpAdapter,你可以在你的服务、过滤器或任何其他地方访问底层HTTP服务器的API,这使得你可以编写更具平台兼容性的代码。

AllExceptionsFilter 通过 httpAdapter 与底层HTTP服务器实现交互例子

typescript 复制代码
import { ArgumentsHost, Catch, ExceptionFilter } from '@nestjs/common';
import { BaseExceptionFilter } from '@nestjs/core';
import { AbstractHttpAdapter } from '@nestjs/core/adapters/http-adapter';

@Catch()
export class AllExceptionsFilter extends BaseExceptionFilter implements ExceptionFilter {
  constructor(private readonly httpAdapter: AbstractHttpAdapter) {
    super();
  }

  catch(exception: unknown, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const request = ctx.getRequest();
    const response = ctx.getResponse();
    const statusCode = exception instanceof HttpException
      ? exception.getStatus()
      : HttpStatus.INTERNAL_SERVER_ERROR;

    // 使用 httpAdapter 发送自定义响应
    this.httpAdapter.reply(response, {
      status: 'error',
      message: 'An unexpected error occurred',
    }, statusCode);
  }
}

在这个例子中,AllExceptionsFilter 捕获了应用中所有没有被其他过滤器处理的异常。在 catch 方法内,我们通过 host.switchToHttp() 获取当前请求和响应的引用,并计算异常应返回的HTTP状态码。如果捕获的异常是一个 HttpException 的实例,我们从异常中获取状态码;否则,我们使用HTTP 500(内部服务器错误)作为默认状态码。

我们使用 httpAdapter.reply() 方法发送响应,而不是直接操作Express或Fastify的响应对象。这样我们的过滤器就不需要知道底层HTTP服务器的具体实现细节,它可以无缝工作在Express、Fastify或任何其他NestJS支持的HTTP平台上。

httpAdapter.reply() 方法接受三个参数:

  1. 原始的 response 对象,这是从NestJS的 ArgumentsHost 中获取的。
  2. 响应体,这个例子中是一个包含错误状态和消息的对象。
  3. HTTP状态码。

这样,无论你的NestJS应用是基于Express还是Fastify,AllExceptionsFilter 都可以正确地工作,因为底层的HTTP交互是通过抽象层 httpAdapter 来处理的,这使得它与底层HTTP服务器实现无关。

2. 使用 APP_FILTER 令牌

1). 定义: 在全局过滤器AllExceptionsFilter中将HttpAdapterHost传递给 BaseExceptionFilter 的构造函数👇🏻

scala 复制代码
@Catch()
export class AllExceptionsFilter extends BaseExceptionFilter {
  // 举例来说,如果有依赖需要注入,可以在构造函数中声明
  constructor(
    adapterHost: HttpAdapterHost,
    private readonly someOtherService: SomeOtherService
  ) {
    super(adapterHost.httpAdapter);
  }
  
  // 异常处理逻辑
  catch(exception: unknown, host: ArgumentsHost) {
    // 这里可以使用someOtherService提供的方法进行日志记录等操作
    this.someOtherService.logSomething('An exception occurred');

    // 调用基类的catch方法继续进行异常处理
    super.catch(exception, host);
  }
}

在构造函数中,super() 用于调用父类构造函数的方式来初始化,而在子类的其他方法中,super.methodName(args...) 用于调用父类中定义的方法。

注意📢:这里把adapterHost传递给父类BaseExceptionFilter 的构造函数就完成任务了,并不需要在子类里使用adapterHost👇🏻

adapterHost 参数,没有使用任何访问修饰符,这意味着 adapterHost 只是一个临时变量,它只在构造函数的执行期间存在。因为 adapterHost 没有被定义为类的成员变量,所以你不能在类的其他方法中直接使用它(除非你单独声明并在构造函数中初始化一个成员变量来存储它的值)。

在这个特定的例子中,adapterHost 只是用来在构造函数中访问它的 httpAdapter 属性,然后将这个 httpAdapter 传递给父类 BaseExceptionFilter 的构造函数(通过 super(adapterHost.httpAdapter))。所以,adapterHost 本身在构造函数之外并不需要被使用。

2). 使用: 在根模块中(AppModule),使用 APP_FILTER 令牌来注册这个全局过滤器AllExceptionsFilter:

typescript 复制代码
// app.module.ts
import { Module } from '@nestjs/common';
import { APP_FILTER } from '@nestjs/core';
import { AllExceptionsFilter } from './all-exceptions.filter';

@Module({
  providers: [
    {
      provide: APP_FILTER,
      useClass: AllExceptionsFilter,
    },
  ],
  // ...其他模块配置
})
export class AppModule {}
相关推荐
丁总学Java14 小时前
微信小程序-npm支持-如何使用npm包
前端·微信小程序·npm·node.js
看到请催我学习16 小时前
如何实现两个标签页之间的通信
javascript·css·typescript·node.js·html5
NiNg_1_23420 小时前
npm、yarn、pnpm之间的区别
前端·npm·node.js
余生H21 小时前
前端的全栈混合之路Meteor篇:关于前后端分离及与各框架的对比
前端·javascript·node.js·全栈
Ink1 天前
从底层看 path.resolve 实现
前端·node.js
奔跑吧邓邓子1 天前
npm包管理深度探索:从基础到进阶全面教程!
前端·npm·node.js
知否技术1 天前
为什么nodejs成为后端开发者的新宠?
前端·后端·node.js
谢尔登2 天前
【Node.js】worker_threads 多线程
node.js
osnet2 天前
showdoc二次开发
node.js·vue
泯泷2 天前
「生产必看」在企业环境中正确使用 Node.js 的九大原则
前端·后端·node.js