Nest.js 实战 (一):使用过滤器优雅地统一处理响应体
创始人
2025-01-07 03:04:15
0

前言

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

{   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 = '请求失败',  } 
  1. src 目录中新建 /typings/index.d.ts 文件:
declare namespace Api {  namespace Common {    /**     * @description: 全局响应体     */    type Response = {      code: number; // 状态码      data?: T; // 业务数据      msg: string; // 响应信息      timestamp: number; // 时间戳    };    /**     * @description: 分页数据     */    type PageResponse = {      current?: number; // 页码      size?: number; // 当前页条数      total?: number; // 总条数      records: T[]; // 业务数据    };  } } 
  1. 我们可以编写一个公共方法,专门处理接口的返回结果:
  import dayjs from 'dayjs';   import { RESPONSE_CODE, RESPONSE_MSG } from '@/enums';  import type { Response } from '@/types';   /**   * @description: 统一返回体   */  export const responseMessage = (    data,    msg: string = RESPONSE_MSG.SUCCESS,    code: number = RESPONSE_CODE.SUCCESS,  ): Response => ({ 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();       // 获取状态码       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();     // 获取状态码,判断是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. 正常请求成功
    在这里插入图片描述

  2. 当我们访问一个不存在的接口时
    在这里插入图片描述

相关内容

热门资讯

一分钟内幕!科乐吉林麻将系统发... 一分钟内幕!科乐吉林麻将系统发牌规律,福建大玩家确实真的是有挂,技巧教程(有挂ai代打);所有人都在...
一分钟揭秘!微扑克辅助软件(透... 一分钟揭秘!微扑克辅助软件(透视辅助)确实是有挂(2024已更新)(哔哩哔哩);1、用户打开应用后不...
五分钟发现!广东雀神麻雀怎么赢... 五分钟发现!广东雀神麻雀怎么赢,朋朋棋牌都是是真的有挂,高科技教程(有挂方法)1、广东雀神麻雀怎么赢...
每日必看!人皇大厅吗(透明挂)... 每日必看!人皇大厅吗(透明挂)好像存在有挂(2026已更新)(哔哩哔哩);人皇大厅吗辅助器中分为三种...
重大科普!新华棋牌有挂吗(透视... 重大科普!新华棋牌有挂吗(透视)一直是有挂(2021已更新)(哔哩哔哩)1、完成新华棋牌有挂吗的残局...
二分钟内幕!微信小程序途游辅助... 二分钟内幕!微信小程序途游辅助器,掌中乐游戏中心其实存在有挂,微扑克教程(有挂规律)二分钟内幕!微信...
科技揭秘!jj斗地主系统控牌吗... 科技揭秘!jj斗地主系统控牌吗(透视)本来真的是有挂(2025已更新)(哔哩哔哩)1、科技揭秘!jj...
1分钟普及!哈灵麻将攻略小,微... 1分钟普及!哈灵麻将攻略小,微信小程序十三张好像存在有挂,规律教程(有挂技巧)哈灵麻将攻略小是一种具...
9分钟教程!科乐麻将有挂吗,传... 9分钟教程!科乐麻将有挂吗,传送屋高防版辅助(总是存在有挂)1、完成传送屋高防版辅助透视辅助安装,帮...
每日必看教程!兴动游戏辅助器下... 每日必看教程!兴动游戏辅助器下载(辅助)真是真的有挂(2025已更新)(哔哩哔哩)1、打开软件启动之...