网站LOGO
白雾茫茫丶
页面加载中
10月18日
网站LOGO 白雾茫茫丶
记录学习、生活和有趣的事
菜单
  • 热评
    用户的头像
    首次访问
    上次留言
    累计留言
    我的等级
    我的角色
    打赏二维码
    打赏博主
    Nest.js 实战 (一):使用过滤器优雅地统一处理响应体
    点击复制本页信息
    微信扫一扫
    文章二维码
    文章图片 文章标题
    创建时间
  • 一 言
    确认删除此评论么? 确认
  • 本弹窗介绍内容来自,本网站不对其中内容负责。
    • 复制图片
    • 复制图片地址
    • 百度识图
    按住ctrl可打开默认菜单

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

    谢明伟 · 原创 ·
    前端开发Nest 实战 · TypeScriptNest
    共 5009 字 · 约 2 分钟 · 498
    本文最后更新于2024年07月15日,已经过了95天没有更新,若内容或图片失效,请留言反馈

    前言

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

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

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

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

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

      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 文件:

      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. 我们可以编写一个公共方法,专门处理接口的返回结果:

      ts 代码:
        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 文件:

    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 文件:

    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 文件:

    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 中注册全局的异常过滤器。

    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. 正常请求成功
    2. 当我们访问一个不存在的接口时
    声明:本文由 谢明伟(博主)原创,依据 CC-BY-NC-SA 4.0 许可协议 授权,转载请注明出处。

    还没有人喜爱这篇文章呢

    现在已有

    5

    条评论
    我要发表评论
    1. 头像
      · · 辽宁-沈阳
      • 等级:Lv.3
      • 角色:访客
      • 在线:很久之前
      头像
      沙发

      是不是该实战2了

      评论
      1. · · 广东-深圳
        • 角色:博主
        • 在线:三月内
        头像

        准备了,打算先更新这个系列,哈哈

        评论
        1. 头像
          · · 辽宁-沈阳
          • 等级:Lv.3
          • 角色:访客
          • 在线:很久之前
          头像

          我说已经有1了啊,这篇文章是不是应该第二个

          评论
          1. · · 广东-深圳
            • 角色:博主
            • 在线:三月内
            头像

            不一样,Nest.js、Next.js和Nuxt.js是三个东西,虽然名字很相似,今年就打算写着三个系列 哈哈

            评论
            1. 头像
              · · 辽宁-沈阳
              • 等级:Lv.3
              • 角色:访客
              • 在线:很久之前
              头像

              啊?没看出来哈哈

              评论
    博客logo 白雾茫茫丶 记录学习、生活和有趣的事 51统计 百度统计
    MOEICP 萌ICP备20236860号 ICP 粤ICP备2023007649号 ICP 粤公网安备44030402006402号

    💻️ 谢明伟 2小时前 在线

    🕛

    本站已运行 2 年 291 天 1 小时 11 分

    🌳

    自豪地使用 Typecho 建站,并搭配 MyLife 主题
    白雾茫茫丶. © 2022 ~ 2024.
    网站logo

    白雾茫茫丶 记录学习、生活和有趣的事