前言
在我們實際的業務開發中,我們可以看到后端接口返回格式都有一定的要求,假如我們統一規定接口的統一返回格式為:
{data: any; // 業務數據code: number; // 狀態碼msg: string; // 響應信息timestamp: number; // 時間戳
}
那么在 Nest.js 中,我們應該如何處理呢?
定義響應狀態碼枚舉和類型
- 在
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 = '請求失敗',}
- 在
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[]; // 業務數據};}
}
- 我們可以編寫一個公共方法,專門處理接口的返回結果:
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();
效果預覽
-
正常請求成功
-
當我們訪問一個不存在的接口時