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

相关文章
|
11天前
|
设计模式 数据安全/隐私保护
Next.js 实战 (七):浅谈 Layout 布局的嵌套设计模式
这篇文章介绍了在Next.js框架下,如何处理中后台管理系统中特殊页面(如登录页)不包裹根布局(RootLayout)的问题。作者指出Next.js的设计理念是通过布局的嵌套来创建复杂的页面结构,这虽然保持了代码的整洁和可维护性,但对于特殊页面来说,却造成了不必要的布局包裹。文章提出了一个解决方案,即通过判断页面的skipGlobalLayout属性来决定是否包含RootLayout,从而实现特殊页面不包裹根布局的目标。
65 33
|
2天前
|
存储 安全 API
Next.js 实战 (九):使用 next-auth 完成第三方身份登录验证
这篇文章介绍了next-auth,一个为Next.js设计的身份验证库,支持多种认证方式,如电子邮件和密码、OAuth2.0提供商(如Google、GitHub、Facebook等)以及自定义提供商。文章包含了如何配置Github Provider以及会话管理,并提到了适配器Adapters在next-auth中的作用。最后,文章强调了next-auth的强大功能值得进一步探索。
23 10
|
3天前
|
中间件 API
Next.js 实战 (八):使用 Lodash 打包构建产生的“坑”?
这篇文章介绍了作者在使用Nextjs15进行项目开发时遇到的部署问题。在部署过程中,作者遇到了打包构建时的一系列报错,报错内容涉及动态代码评估在Edge运行时不被允许等问题。经过一天的尝试和调整,作者最终删除了lodash-es库,并将radash的部分源码复制到本地,解决了打包报错的问题。文章最后提供了项目的线上预览地址,并欢迎读者留言讨论更好的解决方案。
17 10
|
19天前
|
前端开发 API 开发者
Next.js 实战 (五):添加路由 Transition 过渡效果和 Loading 动画
这篇文章介绍了Framer Motion,一个为React设计的动画库,提供了声明式API处理动画和页面转换,适合创建响应式用户界面。文章包括首屏加载动画、路由加载Loading、路由进场和退场动画等主题,并提供了使用Framer Motion和next.js实现这些动画的示例代码。最后,文章总结了这些效果,并邀请读者探讨更好的实现方案。
|
17天前
|
JavaScript 前端开发 API
Next.js 实战 (六):如何实现文件本地上传
这篇文章介绍了在Next.js中如何实现文件上传到本地的方法。文章首先提到Next.js官方文档中没有提供文件上传的实例代码,因此开发者需要自行实现,通常有两种思路:使用Node.js原生上传或使用第三方插件如multer。接着,文章选择了使用Node.js原生上传的方式来讲解实现过程,包括如何通过哈希值命名文件、上传到指定目录以及如何分类文件夹。然后,文章展示了具体的实现步骤,包括编写代码来处理文件上传,并给出了代码示例。最后,文章通过一个效果演示说明了如何通过postman模拟上传文件,并展示了上传后的文件夹结构。
|
1月前
Next.js 实战 (二):搭建 Layouts 基础排版布局
本文介绍了作者在Next.js v15.x版本发布后,对一个旧项目的重构过程。文章详细说明了项目开发规范配置、UI组件库选择(最终选择了Ant-Design)、以及使用Ant Design的Layout组件实现中后台布局的方法。文末展示了布局的初步效果,并提供了GitHub仓库链接供读者参考学习。
Next.js 实战 (二):搭建 Layouts 基础排版布局
|
1月前
|
存储 网络架构
Next.js 实战 (四):i18n 国际化的最优方案实践
这篇文章介绍了Next.js国际化方案,作者对比了网上常见的方案并提出了自己的需求:不破坏应用程序的目录结构和路由。文章推荐使用next-intl库来实现国际化,并提供了详细的安装步骤和代码示例。作者实现了国际化切换时不改变路由,并把当前语言的key存储到浏览器cookie中,使得刷新浏览器后语言不会失效。最后,文章总结了这种国际化方案的优势,并提供Github仓库链接供读者参考。
|
1月前
Next.js 实战 (三):优雅的实现暗黑主题模式
这篇文章介绍了在Next.js中实现暗黑模式的具体步骤。首先,需要安装next-themes库。然后,在/components/ThemeProvider/index.tsx文件中新增ThemeProvider组件,并在/app/layout.tsx文件中注入该组件。如果想要加入过渡动画,可以修改代码实现主题切换时的动画效果。最后,需要在需要的位置引入ThemeModeButton组件,实现暗黑模式的切换。
|
2月前
|
设计模式 前端开发 JavaScript
JavaScript设计模式及其在实战中的应用,涵盖单例、工厂、观察者、装饰器和策略模式
本文深入探讨了JavaScript设计模式及其在实战中的应用,涵盖单例、工厂、观察者、装饰器和策略模式,结合电商网站案例,展示了设计模式如何提升代码的可维护性、扩展性和可读性,强调了其在前端开发中的重要性。
47 2
|
2月前
|
前端开发 JavaScript
JavaScript新纪元:ES6+特性深度解析与实战应用
【10月更文挑战第29天】本文深入解析ES6+的核心特性,包括箭头函数、模板字符串、解构赋值、Promise、模块化和类等,结合实战应用,展示如何利用这些新特性编写更加高效和优雅的代码。
57 0