前言
在我们实际的业务开发中,我们可以看到后端接口返回格式都有一定的要求,假如我们统一规定接口的统一返回格式为:
{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();
效果预览
-
正常请求成功
-
当我们访问一个不存在的接口时