「项目实战」从0搭建NestJS后端服务(五):统一的响应拦截和异常错误过滤

从0搭建NestJS后端服务(五):统一的响应拦截和异常错误过滤

前言

大家好,我是elk。今天我们要给API接口们统一换装啦!想象一下,当你的女朋友每次出门都穿不同风格的衣服,你是不是更希望她每天穿情侣装呢?后端接口也一样,统一的响应格式能让前端开发更轻松。本文就教大家如何用NestJS给所有接口穿上"统一工装"!

为什么要统一格式?

先看两个典型场景:

场景1:成功响应

json 复制代码
// 没穿工装
{ "id": 1, "name": "张三" }

// 穿上工装
{
  "code": 200,
  "message": "请求成功",
  "data": { "id": 1, "name": "张三" }
}

场景2:错误响应

json 复制代码
// 没穿工装
"用户不存在"

// 穿上工装
{
  "code": 404,
  "message": "用户不存在",
  "path": "/users/999",
  "timestamp": "2025-03-25T19:00:00Z"
}

统一格式的好处:

  1. 前端一眼看出请求状态(看code)
  2. 错误信息结构化,方便调试
  3. 接口文档更规范
  4. 客户端处理响应更统一

目录结构

markdown 复制代码
- src
  - common
    -filters
      -all-exceptions.filter.ts
    -Interceptors
      -response.interceptor.ts
    -interfaces
      -api-response.ts

接口定义

api-response.ts

typescript 复制代码
export interface ApiResponse<T> {
  code: number;
  message: string;
  data?: T;
}
export interface ErrorResponse {
  code: number;
  message: string;
  error: string;
  path: string;
  timestamp: string;
}

响应拦截器的处理

想象你开了一家快递公司,拦截器就像包装部门,给所有包裹套上统一包装盒。

response.interceptor.ts

typescript 复制代码
// 从@nestjs/common导入所需的装饰器和接口
import {
  CallHandler,
  ExecutionContext,
  Injectable,
  NestInterceptor,
} from '@nestjs/common';
// 导入RxJS的Observable
import { Observable } from 'rxjs';
// 导入RxJS的map操作符
import { map } from 'rxjs/operators';
// 导入自定义的ApiResponse接口
import { ApiResponse } from '@/common/interfaces/api-response';
// 使用Injectable装饰器,将该类标记为可注入的拦截器
@Injectable()
export class ResponseInterceptor<T>
  implements NestInterceptor<T, ApiResponse<T>>
{
  // 实现拦截器方法,用于处理响应数据
  intercept(
    context: ExecutionContext, // 执行上下文
    next: CallHandler, // 下一个处理程序
  ): Observable<ApiResponse<T>> {
    return next.handle().pipe(
      // 使用map操作符转换响应数据
      map((data) => ({
        code: 200, // 响应状态码
        message: '请求成功', // 响应消息
        data, // 实际响应数据
      })),
    );
  }
}

异常过滤器的处理

当包裹运输出现问题,客服中心要统一处理投诉反馈。

all-exceptions.filter.ts

typescript 复制代码
// 从@nestjs/common导入所需的装饰器和接口
import {
  ArgumentsHost,
  Catch,
  ExceptionFilter,
  HttpException,
  HttpStatus,
} from '@nestjs/common';
// 从express导入Response和Request类型
import { Response, Request } from 'express';
​
import { ApiResponse } from '../interfaces/api-response';
​
// 使用Catch装饰器,指定捕获HttpException类型的异常
@Catch(HttpException)
export class AllExceptionsFilter implements ExceptionFilter {
  // 实现catch方法,处理捕获的异常
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp(); // 获取HTTP上下文
    const response = ctx.getResponse<Response>(); // 获取响应对象
    const request = ctx.getRequest<Request>(); // 获取请求对象
    const status =
      exception instanceof HttpException
        ? exception.getStatus()
        : HttpStatus.INTERNAL_SERVER_ERROR; // 获取状态码,默认为500
    const message =
      exception instanceof HttpException ? exception.message : '服务器错误'; // 获取错误信息,默认为'服务器错误'
    // 返回统一的错误响应格式
    response.status(status).json({
      code: status, // 状态码
      message, // 错误信息
      timestamp: new Date().toISOString(), // 时间戳
      path: request.url, // 请求路径
    });
  }
}
​

全局注册

  • main.ts
javascript 复制代码
// 引入全局响应拦截器
import { ResponseInterceptor } from './common/Interceptors/response.interceptor';
// 引入全局异常过滤器
import { AllExceptionsFilter } from '@/common/filters/all-exceptions.filter';
​
// 全局响应拦截器
app.useGlobalInterceptors(new ResponseInterceptor());
// 全局异常过滤器
app.useGlobalFilters(new AllExceptionsFilter());

案例验证

成功案例:

bash 复制代码
GET /system/user/1

{
  "code": 200,
  "message": "请求成功",
  "data": {
    "id": 1,
    "name": "张三"
  }
}

失败案例:

bash 复制代码
GET /system/user/999

{
  "code": 404,
  "message": "用户不存在",
  "path": "/users/999",
  "timestamp": "2023-08-15T10:00:00Z"
}

📍 下期预告

《从0搭建NestJS后端服务(六):日志系统的集成》

我们将探讨:

  • 如何选择合适日志库
  • 如何配置日志级别和输出格式
  • 如何实现日志的集中管理

🤝 互动时间

遇到问题?有更好的建议?欢迎留言交流!

  • 当接口返回{ data: null }时,前端应该如何优雅处理?
  • 如何设计多层级业务错误码体系(如10001代表手机号已注册)?
  • 在微服务架构下,如何保持跨服务异常传递的一致性?

一起交流成长,让开发更高效!🚀

相关推荐
有人说风轻的像雨9 小时前
使用 Node.js 和 163 邮箱发送邮件
node.js
还是鼠鼠13 小时前
Node.js 监听 GET 和 POST 请求并处理参数
前端·javascript·vscode·node.js·json
bnnnnnnnn13 小时前
宝塔面板快速部署 Node.js + Express 后端,一步到位!
前端·后端·node.js
编代码的小王14 小时前
Node.js 批量修改文件名脚本
node.js
南囝coding14 小时前
做定时任务,一定要用这个神库!!
前端·面试·node.js
前端的阶梯14 小时前
Electron中深度解读实现多tabs的几种方式
electron·node.js
莫循瑾木18 小时前
莫循跃迁:nvm管理node版本速通
前端·后端·node.js
还是鼠鼠1 天前
认识 Express.js:Node.js 最流行的 Web 框架
开发语言·前端·javascript·vscode·node.js·json·express
zxg_神说要有光1 天前
Three.js 小册上线了,我最重要的一部作品
前端·javascript·node.js
不想说话的麋鹿1 天前
「项目实战」从0搭建NestJS后端服务(六):日志系统的集成
前端·node.js·全栈