Nest.js 实战 (一):使用过滤器优雅地统一处理响应体

简介: 这篇文章介绍了在Nest.js中如何处理接口统一返回格式的方法。首先定义了响应状态码枚举和类型,然后创建了HttpException异常过滤器来捕获HttpException类的异常并设置自定义响应逻辑。最后通过全局配置和效果预览展示了如何应用这些设置。

前言

在我们实际的业务开发中,我们可以看到后端接口返回格式都有一定的要求,假如我们统一规定接口的统一返回格式为:

{
   
   
  data: any; // 业务数据
  code: number; // 状态码
  msg: string; // 响应信息
  timestamp: number; // 时间戳
}

那么在 Nest.js 中,我们应该如何处理呢?

定义响应状态码枚举和类型

  1. src 目录中新建 /enums/index.ts 文件:

    /**
    * @description: 响应码
    */
    export enum RESPONSE_CODE {
         
         
    NOSUCCESS = -1, // 表示请求成功,但操作未成功
    SUCCESS = 200, // 请求成功
    BAD_REQUEST = 400, // 请求错误
    UNAUTHORIZED = 401, // 未授权
    FORBIDDEN = 403, // 禁止访问
    NOT_FOUND = 404, // 资源未找到
    INTERNAL_SERVER_ERROR = 500, // 服务器错误
    }
    
    /**
    * @description: 请求提示语
    */
    export enum RESPONSE_MSG {
         
         
    SUCCESS = '请求成功',
    FAILURE = '请求失败',
    }
    
  2. src 目录中新建 /typings/index.d.ts 文件:
    declare namespace Api {
         
         
    namespace Common {
         
         
    /**
     * @description: 全局响应体
     */
    type Response<T = any> = {
         
         
      code: number; // 状态码
      data?: T; // 业务数据
      msg: string; // 响应信息
      timestamp: number; // 时间戳
    };
    /**
     * @description: 分页数据
     */
    type PageResponse<T = any> = {
         
         
      current?: number; // 页码
      size?: number; // 当前页条数
      total?: number; // 总条数
      records: T[]; // 业务数据
    };
    }
    }
    
  3. 我们可以编写一个公共方法,专门处理接口的返回结果:

    import dayjs from 'dayjs';
    
    import {
         
          RESPONSE_CODE, RESPONSE_MSG } from '@/enums';
    import type {
         
          Response } from '@/types';
    
    /**
    * @description: 统一返回体
    */
    export const responseMessage = <T = any>(
    data,
    msg: string = RESPONSE_MSG.SUCCESS,
    code: number = RESPONSE_CODE.SUCCESS,
    ): Response<T> => ({
         
          data, msg, code, timestamp: dayjs().valueOf() });
    

    这里大家可以根据自己的实际业务需求修改。

定义响应体 DTO

首先,定义一个统一的响应数据传输对象(DTO),这将作为所有 API 响应的基本结构。

src 目录中新建 /dto/response.dto.ts 文件:

import {
   
    ApiProperty } from '@nestjs/swagger';

import {
   
    RESPONSE_CODE, RESPONSE_MSG } from '@/enums';

export class ResponseDto {
   
   
  @ApiProperty({
   
   
    type: Number,
    description: '业务状态码',
    default: RESPONSE_CODE.SUCCESS,
  })
  code: number;

  @ApiProperty({
   
   
    type: String,
    description: '业务信息',
    default: RESPONSE_MSG.SUCCESS,
  })
  msg: string;

  @ApiProperty({
   
    description: '业务数据' })
  data?: any;

  @ApiProperty({
   
    type: Number, description: '时间戳', default: 1720685424078 })
  timestamp: number;
}

HttpException 异常过滤器

创建一个异常过滤器,它负责捕获作为 HttpException 类实例的异常,并为它们设置自定义响应逻辑。

src 目录中新建 /filter/http-exception.filter.ts 文件:

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

  import {
   
    responseMessage } from '@/utils';

  // @Catch() 装饰器绑定所需的元数据到异常过滤器上。它告诉 Nest这个特定的过滤器正在寻找
  @Catch(HttpException)
  export class HttpExceptionsFilter implements ExceptionFilter {
   
   
    catch(exception: HttpException, host: ArgumentsHost) {
   
   
      // 获取上下文
      const ctx = host.switchToHttp();
      // 获取响应体
      const response = ctx.getResponse<Response>();
      // 获取状态码
      const statusCode = exception.getStatus();

      // 自定义异常返回体
      response.status(statusCode).json(responseMessage(null, exception.message, statusCode));
    }
 }

全局异常过滤器

创建一个全局异常过滤器来处理所有的异常,并将其转换为统一的响应格式。

src 目录中新建 /filter/all-exception.filter.ts 文件:

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

import {
   
    responseMessage } from '@/utils';

// @Catch() 装饰器绑定所需的元数据到异常过滤器上。它告诉 Nest这个特定的过滤器正在寻找
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
   
   
  catch(exception: unknown, host: ArgumentsHost) {
   
   
    // 获取上下文
    const ctx = host.switchToHttp();
    // 获取响应体
    const response = ctx.getResponse<Response>();
    // 获取状态码,判断是HTTP异常还是服务器异常
    const statusCode =
      exception instanceof HttpException
        ? exception.getStatus()
        : HttpStatus.INTERNAL_SERVER_ERROR;

    // 自定义异常返回体
    response
      .status(statusCode)
      .json(responseMessage(null, '服务器内部错误!', statusCode));
  }
}

全局配置

main.ts 中注册全局的异常过滤器。

import {
   
    NestFactory } from '@nestjs/core';
import {
   
    AppModule } from './app.module';
import {
   
    AllExceptionsFilter } from '@/filter/all-exception.filter'; // 全局异常过滤器
import {
   
    HttpExceptionsFilter } from '@/filter/http-exception.filter'; // http 异常过滤器

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

  // 错误异常捕获 和 过滤处理
  app.useGlobalFilters(new AllExceptionsFilter());
  app.useGlobalFilters(new HttpExceptionsFilter());

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

效果预览

  1. 正常请求成功
    6hexh81jztsuhxicahzqmezxhgrza9l5.png

  2. 当我们访问一个不存在的接口时
    88q34h8mipfysadrbvzu0u0j3152g60v.png

相关文章
|
6天前
|
缓存 中间件
Nest.js 实战 (九):使用拦截器记录用户 CURD 操作日志
这篇文章介绍了在Nest.js中如何实现记录用户CURD操作的需求。首先解释了什么是拦截器以及拦截器的作用,然后通过创建Prisma模型,添加Log模型,并通过编写LoggerInterceptor拦截器,实现了记录用户操作的功能。最后通过效果演示和总结,强调了使用拦截器实现此功能的有效性。
|
4天前
|
JavaScript 前端开发
JavaScript基础&实战(1)js的基本语法、标识符、数据类型
这篇文章是JavaScript基础与实战教程的第一部分,涵盖了JavaScript的基本语法、标识符、数据类型以及如何进行强制类型转换,通过代码示例介绍了JS的输出语句、编写位置和数据类型转换方法。
JavaScript基础&实战(1)js的基本语法、标识符、数据类型
|
13天前
|
JavaScript
Nest.js 实战 (七):如何生成 SVG 图形验证码
这篇文章介绍了使用NestJS实现Session验证的图形验证码功能的具体步骤。首先,通过powershell代码安装依赖pnpmaddsvg-captcha。然后,在控制器中使用TypeScript代码引入相关依赖,创建一个图形验证码的接口,当请求该接口时,返回一张随机图片验证码。最后,进行了效果演示。
Nest.js 实战 (七):如何生成 SVG 图形验证码
|
4天前
|
JavaScript 前端开发
JavaScript基础&实战 JS中正则表达式的使用
这篇文章介绍了JavaScript中正则表达式的使用,包括正则表达式的创建、匹配模式、字符串匹配、拆分、搜索、匹配和替换等方法,并通过示例代码展示了如何应用这些技术。
JavaScript基础&实战 JS中正则表达式的使用
|
4天前
|
JavaScript 前端开发
JavaScript基础&实战(5)js中的数组、forEach遍历、Date对象、Math、String对象
这篇文章介绍了JavaScript中的数组、Date对象、Math对象以及包装类(String、Number、Boolean),并详细讲解了数组的创建、方法(如forEach、push、pop、unshift、slice、splice)和遍历操作,以及工厂方法创建对象和原型对象的概念。
JavaScript基础&实战(5)js中的数组、forEach遍历、Date对象、Math、String对象
|
4天前
|
JavaScript 前端开发
JavaScript基础&实战(4)js中的对象、函数、全局作用域和局部作用域
这篇文章介绍了JavaScript中对象的基本概念和操作,包括对象属性和方法的使用、对象字面量的创建、函数的定义和作用域的概念,以及全局作用域和局部作用域的区别和特性。
JavaScript基础&实战(4)js中的对象、函数、全局作用域和局部作用域
|
4天前
|
JavaScript 前端开发
JavaScript基础&实战(3)js中的流程控制语句、条件分支语句、for循环、while循环
这篇文章讲解了JavaScript中的流程控制语句,包括基本的if条件判断、弹窗提示输入、switch条件分支语句、while和do...while循环以及for循环的使用和示例。
JavaScript基础&实战(3)js中的流程控制语句、条件分支语句、for循环、while循环
|
4天前
|
JavaScript 前端开发
JavaScript基础&实战(2)js中的强制类型转换、运算符、关系运算符、逻辑运算符、条件运算符
这篇文章详细介绍了JavaScript中的强制类型转换、运算符(包括算术、逻辑、条件、赋值和关系运算符)的使用方法和优先级规则。
JavaScript基础&实战(2)js中的强制类型转换、运算符、关系运算符、逻辑运算符、条件运算符
|
12天前
|
JSON 数据安全/隐私保护 数据格式
Nest.js 实战 (八):基于 JWT 的路由身份认证鉴权
这篇文章介绍了身份验证的重要性和多种处理策略,重点放在了JWT(JSON Web Token)认证在Nest.js框架中的应用。文章包含了JWT认证的流程,如何在Nest.js中实现,以及如何创建JWT认证策略。包括了安装依赖,创建处理认证流程的文件,以及如何使用HttpException过滤器来处理未登录访问。
Nest.js 实战 (八):基于 JWT 的路由身份认证鉴权
|
7天前
|
JavaScript 数据安全/隐私保护 Python
东方财富股票数据JS逆向:secids字段和AES加密实战
东方财富股票数据JS逆向:secids字段和AES加密实战
25 0