Skip to content

NestJS 异常过滤器

基础语法

自定义异常过滤器必须实现 ExceptionFilter 接口(来自 @nestjs/common),该接口仅定义一个 catch 方法:

ts
interface ExceptionFilter<T = any> {
  catch(exception: T, host: ArgumentsHost): void;
}

参数说明

shell
# 基础参数
exception: 捕获到的异常实例(类型可通过泛型限定)
ArgumentsHost: 执行上下文封装器,核心作用是适配不同运行环境(HTTP / 微服务 / WebSocket),并获取请求、响应等核心对象。

# ArgumentsHost 下的方法
getType() 获取当前环境类型(http/rpc/ws)
switchToHttp() 切换到 HTTP 上下文,返回 HttpArgumentsHost
switchToRpc() 切换到微服务 RPC 上下文,返回 RpcArgumentsHost
switchToWs() 切换到 WebSocket 上下文,返回 WsArgumentsHost
getArgs() 获取原始参数数组(不同环境参数不同,HTTP 下为 [req, res, next]

# ArgumentsHost 下的 switchToHttp() 下的方法
getRequest(): 获取 Express/Fastify 的 req 对象;
getResponse(): 获取 Express/Fastify 的 res 对象;
getNext(): 获取 Express/Fastify 的 next 函数。

自定义异常过滤器

以处理 HTTP 异常为例,创建 http-exception.filter.ts

ts
// src/filters/http-exception.filter.ts
import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common';
import { Request, Response } from 'express';

// @Catch 装饰器指定要捕获的异常类型(可传多个,如 @Catch(HttpException, Error))
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  // 核心方法:捕获异常后执行的逻辑
  catch(exception: HttpException, host: ArgumentsHost) {
    // 1. 获取请求上下文(支持不同执行上下文:HTTP/RPC/WebSocket)
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();

    // 2. 提取异常信息
    const status = exception.getStatus(); // HTTP 状态码
    const exceptionResponse = exception.getResponse(); // 异常响应体(字符串/对象)

    // 3. 标准化响应格式
    const errorResponse = {
      code: status,
      timestamp: new Date().toISOString(),
      path: request.url,
      message:
        typeof exceptionResponse === 'string'
          ? exceptionResponse
          : (exceptionResponse as any).message || '请求失败',
      data: null,
    };

    // 4. 返回自定义响应
    response.status(status).json(errorResponse);

    // 可选:记录异常日志
    console.error(`[${new Date().toLocaleString()}] ${request.method} ${request.url}`, exception);
  }
}

自定义业务异常

实际开发中,常需要自定义业务异常(如 “用户不存在”“参数校验失败”),结合过滤器处理

  1. 创建自定义异常类
ts
// src/exceptions/business.exception.ts
import { HttpException, HttpStatus } from '@nestjs/common';

// 业务异常类(继承 HttpException)
export class BusinessException extends HttpException {
  // 自定义属性:业务错误码
  private readonly businessCode: number;

  constructor(
    businessCode: number,
    message: string,
    statusCode: HttpStatus = HttpStatus.BAD_REQUEST
  ) {
    super({ businessCode, message }, statusCode);
    this.businessCode = businessCode;
  }

  getBusinessCode(): number {
    return this.businessCode;
  }
}
  1. 改造过滤器支持业务异常
ts
// src/filters/http-exception.filter.ts
import { ExceptionFilter, Catch, ArgumentsHost, HttpException } from '@nestjs/common';
import { Request, Response } from 'express';
import { BusinessException } from '../exceptions/business.exception';

// 同时捕获 HttpException 和 BusinessException
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();
    const status = exception.getStatus();

    // 区分业务异常和普通 HTTP 异常
    if (exception instanceof BusinessException) {
      const businessCode = exception.getBusinessCode();
      const exceptionResponse = exception.getResponse() as { message: string };
      response.status(status).json({
        code: businessCode, // 业务错误码
        timestamp: new Date().toISOString(),
        path: request.url,
        message: exceptionResponse.message,
        data: null,
      });
    } else {
      // 普通 HTTP 异常处理逻辑(同之前)
      const exceptionResponse = exception.getResponse();
      const errorResponse = {
        code: status,
        timestamp: new Date().toISOString(),
        path: request.url,
        message:
          typeof exceptionResponse === 'string'
            ? exceptionResponse
            : (exceptionResponse as any).message || '请求失败',
        data: null,
      };
      response.status(status).json(errorResponse);
    }
  }
}
  1. 使用自定义业务异常
ts
// src/app.controller.ts
import { Controller, Get, HttpStatus } from '@nestjs/common';
import { BusinessException } from './exceptions/business.exception';

@Controller()
export class AppController {
  @Get('business-error')
  throwBusinessError() {
    // 抛出业务异常:错误码 1001,提示“用户不存在”
    throw new BusinessException(1001, '用户不存在', HttpStatus.NOT_FOUND);
  }
}