第十七章 自定义ExceptionFilter

news2024/9/22 1:02:55

在nestjs中,Exception Filter(异常过滤器)是用于处理全局异常的一种机制。它可以捕获应用程序中发生的异常,并对其进行统一处理。本章我们来学习自定义Exception Filter。

首先 先创建一个新的项目:

nest new exception-filter

1719630765771.png
启动项目:

npm run start:dev

1719634571168.png
在controller 里抛个异常,修改app.controller.ts:

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

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

  @Get()
  getHello(): string {
    throw new HttpException('xxxxx', HttpStatus.BAD_REQUEST)
    return this.appService.getHello();
  }
}

HttpStatus 其实就是内置的一些状态码
1719636411087.png
此时 游览器访问 http://localhost:3000/ 可以看到返回的响应是400
1719636511371.png
以上返回的响应格式是内置 Exception Filter 生成
同时 也可以直接抛出具体的异常

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

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

  @Get()
  getHello(): string {
    // throw new HttpException('xxxxx', HttpStatus.BAD_REQUEST)
    throw new BadRequestException('异常');
    return this.appService.getHello();
  }
}

继续游览器访问 http://localhost:3000/
1719636798754.png
接着我们定义一个 exception filter:

nest g filter test --flat --no-spec

1719636975288.png
修改 test.filter.ts:

import { ArgumentsHost, BadRequestException, Catch, ExceptionFilter } from '@nestjs/common';

@Catch(BadRequestException)
export class TestFilter implements ExceptionFilter {
  catch(exception: BadRequestException, host: ArgumentsHost) {
    const http = host.switchToHttp()

    const response = http.getResponse()

    const statusCode = exception.getStatus()

    response.status(statusCode).json({
      code: statusCode,
      message: exception.message,
      error: 'Bad Request',
      xxx: 111
    })
  }
}

在AppModule 里全局引入:

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { TestFilter } from './test.filter';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  app.useGlobalFilters(new TestFilter())

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

访问 http://localhost:3000/ 可以看到响应是自定义的
1719638775133.png
但是目前只是@Catch 了 BadRequestException的异常 如果抛出的是其他异常 那么依然是原来的格式
例如使用BadGatewayException 格式

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

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

  @Get()
  getHello(): string {
    // throw new HttpException('xxxxx', HttpStatus.BAD_REQUEST)
    throw new BadGatewayException('异常');
    return this.appService.getHello();
  }
}

再访问 http://localhost:3000/ 可以看到依然是默认格式
1719639090326.png
接下来我们看一下BadRequestException 和 BadGatewayException 都是哪里来的
1719639180280.png
1719639260748.png
可以看到 BadRequestException 和 BadGatewayException 都是 HttpException 的子类
那么我们在异常过滤那里将 @Catch 指定 HttpException 即可包含所有

@Catch(HttpException)
export class TestFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const http = host.switchToHttp()

    const response = http.getResponse()

    const statusCode = exception.getStatus()

    response.status(statusCode).json({
      code: statusCode,
      message: exception.message,
      error: 'Bad Request',
      xxx: 111
    })
  }
}

再次访问 http://localhost:3000/ 可以看到现在的格式是自定义的格式
1719639389756.png
自此HttpException 都会被处理,但是当我们用 ValidationPipe 也有问题例如:
创建 www.dto.ts

export class WwwDto {
    aaa: string;
    bbb: number;
}

创建接口

  @Post('www')
  www(@Body() www: WwwDto) {
    return www
  }

安装需要用到的包:

npm install --save class-validator class-transformer

接着修改WwwDto 添加校验规则:

import { IsEmail, IsNotEmpty, IsNumber } from "class-validator";

export class WwwDto {
    @IsNotEmpty({ message: 'aaa 不能为空' })
    @IsEmail({}, { message: 'aaa 不是邮箱格式' })
    aaa: string;

    @IsNumber({}, { message: 'bbb 不是数字' })
    @IsNotEmpty({ message: 'bbb 不能为空' })
    bbb: number;
}

接着全局使用ValidationPipe:

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

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  app.useGlobalFilters(new ValidationPipe() as any)

  app.useGlobalFilters(new TestFilter())

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

最后在postman 里测试一下:
1719640439889.png
可以看到提示的错误不对, exception filter 会拦截所有 HttpException,但是没有对这种情况做支持。
我们再次把  app.useGlobalFilters(new TestFilter()) 注释掉
访问
1719640659914.png
接着我们修改 test.filter.ts 实现对ValidationPipe的支持

import { ArgumentsHost, BadRequestException, Catch, ExceptionFilter, HttpException } from '@nestjs/common';

@Catch(HttpException)
export class TestFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const http = host.switchToHttp()

    const response = http.getResponse()

    const statusCode = exception.getStatus()

    const res = exception.getResponse() as { message: string[] };

    response.status(statusCode).json({
      code: statusCode,
      message: res?.message?.join ? res?.message?.join(',') : exception.message,
      error: 'Bad Request',
      xxx: 111
    })
  }
}
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { TestFilter } from './test.filter';
import { ValidationPipe } from '@nestjs/common';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  app.useGlobalPipes(new ValidationPipe())

  app.useGlobalFilters(new TestFilter())

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

1719640859043.png
自此ValidationPipe 的错误和其他的错误就都返回了正确的格式

如果想在 Filter 里注入 AppService 则需要修改注册方式:

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

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  app.useGlobalPipes(new ValidationPipe())

 // app.useGlobalFilters(new TestFilter())

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

接着在 AppModule 里注册一个 token 为 APP_FILTER 的 provider:

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { APP_FILTER } from '@nestjs/core';
import { TestFilter } from './test.filter';

@Module({
  imports: [],
  controllers: [AppController],
  providers: [
    AppService,
    {
      provide: APP_FILTER,
      useClass: TestFilter
    }
  ],
})
export class AppModule { }

Nest 会把所有 token 为 APP_FILTER 的 provider 注册为全局 Exception Filter
接着就可以在TestFilter 注入 AppService

import { ArgumentsHost, BadRequestException, Catch, ExceptionFilter, HttpException, Inject } from '@nestjs/common';
import { AppService } from './app.service';

@Catch(HttpException)
export class TestFilter implements ExceptionFilter {

  @Inject(AppService)
  private service: AppService
  catch(exception: HttpException, host: ArgumentsHost) {
    const http = host.switchToHttp()

    const response = http.getResponse()

    const statusCode = exception.getStatus()

    const res = exception.getResponse() as { message: string[] };

    response.status(statusCode).json({
      code: statusCode,
      message: res?.message?.join ? res?.message?.join(',') : exception.message,
      error: 'Bad Request',
      xxx: 111,
      www: this.service.getHello()
    })
  }
}

访问 http://localhost:3000/
1719641426835.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1916149.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python requests爬虫

Python的requests库是一个强大且易于使用的HTTP库,用于发送HTTP请求和处理响应。它是Python中最受欢迎的网络爬虫框架之一,被广泛用于从网页中提取数据、爬取网站和进行API调用。 使用requests库,你可以轻松地发送各种HTTP请求,包…

buuctf zip伪加密

[BUUCTF]zip伪加密_buuctf zip伪加密-CSDN博客 借鉴以上博客 010打开 这两个位置是计算机判断是否为加密文件 两个都为09(奇数) 一般为真加密 两个为偶数(00)不加密 一个奇数一个偶数,伪加密 (注意,是一般) 这道题两个奇数,以为是真加密 暴力解码一下,解不出 看到题目提…

支持老挝语语音识别、老挝文字OCR识别的《老挝语翻译通》有入门发音教程和大量词汇可以学习!

对于泰国越南等国家大家相必非常熟悉,但是对于同在东南亚的老挝国家,大家可能一时半会还想不起来。 如果你正在学习老挝语或者准备去探索老挝这个国家,那么你从现在开始就要掌握一些基本的老挝语单词和句子了,《老挝语翻译通》Ap…

道路标志线检测数据集(包括VOC/Yolo格式,包括yolov8训练好的模型)

道路标志线检测是指使用计算机视觉技术来识别和提取道路上的标志线(如车道线、停止线、人行横道线等)的位置和形状。这种检测技术广泛应用于自动驾驶系统、驾驶辅助系统(ADAS)、交通监控系统等领域。 本数据集包括:数…

openfoam生成的非均匀固体Solid数据分析、VTK数据格式分析、以及paraview官方用户指导文档和使用方法

一、openfoam生成的非均匀固体Solid数据分析 对于Solid/dealii-output文件,固体的数据文件, # vtk DataFile Version 3.0 #This file was generated by the deal.II library on 2024/7/10 at 9:46:15 ASCII DATASET UNSTRUCTURED_GRIDPOINTS 108000 do…

用Racket做一个拼图游戏——4 实现工具

4 实现工具 思路理清楚了,接下来就一个一个功能实现。在阐述实现功能的编程过程中,会延伸讲解编程思路、相关的Racket函数及相关知识点,力图达到在实践中的学习目的。 在编程实现过程中,首先实现图片操作功能,再通过…

AVLTree

目录 一、概念 二、插入 1.KV模型的AVL树结点定义 2.插入 1.按照BST的规则先插入 2.更新平衡因子 3.旋转的4种情况 1.左单旋 2.右单旋 3.左右双旋 4.右左双旋 三、AVL树的判断 假设程序出了问题,怎么分析 一、概念 二叉搜索树所具有的问题: 将排…

松下的台灯值得入手吗?书客|飞利浦护眼台灯真实测评PK

在追求高效阅读与舒适生活的今天,一盏好的台灯不仅是照明的工具,更是呵护双眼的伴侣。它不仅能够提供额外的光线,还能减少眼睛疲劳,提高我们的工作和学习效率。随着市场的不断发展,护眼台灯品牌款式愈发丰富。因此我们…

U-net和U²-Net网络详解

目录 U-Net: Convolutional Networks for Biomedical Image Segmentation摘要U-net网络结构pixel-wise loss weight U-Net: Going Deeper with Nested U-Structure for Salient Object Detection摘要网络结构详解整体结构RSU-n结构RSU-4F结构saliency map fusion module -- 显著…

怎么选择渲染农场?渲染100邀请码1a12

市面上的渲染农场那么多,到底选择哪一个呢?这次我给大家提供几个指标,以供参考。 1、机器性能:农场的机器性能会直接影响到渲染速度,速度越快项目就能越早完成,所以机器性能是重要的衡量指标。2、渲染价格…

高效应对网络攻击,威胁检测响应(XDR)平台如何提升企业应急响应能力

在数字化时代,企业面临的网络攻击威胁持续增加,如恶意软件、勒索软件、钓鱼攻击、DDoS攻击等。这些威胁不仅危及企业数据安全、系统稳定,还损害了品牌形象和市场信任。随着云计算、大数据、物联网的广泛应用,企业网络攻击面扩大&a…

领夹麦克风哪个品牌好,哪个麦克风好,热门无线麦克风品牌推荐

​无线领夹麦克风是现代沟通的重要工具,它不仅提高了语音交流的清晰度,还展现了使用者的专业形象。随着技术发展,这些麦克风已经变得更加轻便、时尚,易于使用。在各种场合,如演讲、教育和网络直播中,当然&a…

docker-compose构建、运行多容器简介

(1)准备依赖的镜像,包括mariadb、jdk1.8、nginx,配置docker-compose.yml文件 services:mariadb:image: mariadbports:- "3314:3306"environment:- MARIADB_ROOT_PASSWORD123456volumes:- ./mysql:/var/lib/mysqlnetwor…

视频调色的技巧和方法 视频调色的操作步骤 视频调色用什么软件好免费 会声会影下载免费中文版

学会视频调色,就等于掌握了剪辑艺术的密码。视频调色不是为了画面好看,而是通过精心构思的色彩参数,向观众传达作品的情绪和内涵。普通剪辑师与剪辑高手之间的差距,就在于能否领悟视频调色的真谛。 一、视频调色有什么用 掌握混…

SpringBoot配置flyway

背景 目前我们的项目代码都会交由Git、SVN等版本管理工具进行管理,但是我们的sql脚本,尤其是各类ddl脚本并没有进行版本的管理(python的web框架Django默认就提供了类似的工具,从一开始就鼓励开发者通过版本管理的方式进行数据库的…

计算机前端面试题总结-暑期实习(答案补充2)

目录 技术方面 二、js 1.js数据类型 1)值类型(基本类型) 2)引用数据类型(对象类型) ​编辑 2.判断数据类型是否为数组类型 1)Array.isArray() 2)instanceof操作符 3) Object.prototyp…

【分布式系统】Ceph应用之资源池pool管理

目录 一.资源池Pool管理 1.查看资源池信息 1.1.查看资源池副本的数量 1.2.查看 PG 和 PGP 数量 2.修改资源池 2.1.修改 pg_num 和 pgp_num 的数量为 128 2.2.修改 Pool 副本数量为 2 2.3.修改默认副本数为 2 2.4.推送 ceph.conf 配置文件给所有 mon 节点 2.5.去node节…

搭建企业平台:聚合优势资源,优化服务

国际数字影像产业园在加强服务支持与资源整合方面取得了显著成效。通过提供全生命周期服务方案、搭建多元化服务平台、提供政策咨询与行政审批支持、技术与创新支持等措施,为入园企业提供了全方位、便捷、高效的服务支持。同时,通过整合产业链资源、加强…

Xshell配置ssh免密码登录(密钥登陆)

文章目录 一、Xshell登陆步骤 一、Xshell登陆步骤 1.生成客户端的公钥私钥 2.生成公钥文件 3.生成私钥文件 4.将公钥传输进要登录的服务器中 5.修改公钥文件名为authorized_keys (authorized_keys是用于存储公钥的特殊文件,如果已经有了这份文件,可以在末尾追加) 6.连…

香橙派5plus上跑云手机方案二 waydroid

前言 上篇文章香橙派5plus上跑云手机方案一 redroid(带硬件加速)说了怎么跑带GPU加速的redroid方案,这篇说下怎么在香橙派下使用Waydroid。 温馨提示 虽然能运行,但是体验下来只能用软件加速,无法使用GPU加速,所有会很卡。而且…