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