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

- 当我们访问一个不存在的接口时

评论