You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Koa与routing-controllers的通用错误处理方案问询

搞定routing-controllers通用自定义错误处理方案

刚好我之前做过类似的需求,给你一套完整的实现方案,完美匹配你的要求——捕获控制器里所有被拒绝的Promise,返回自定义响应体,根据错误类型设置HTTP状态码,彻底抛弃Koa默认的错误处理(再也不会返回堆栈跟踪这类对用户不友好的内容了)。

第一步:定义自定义错误类

首先得创建我们自己的错误基类,继承原生Error,这样能方便区分不同错误类型,还能携带状态码和额外信息:

export class CustomError extends Error {
  public statusCode: number;
  public message: string;
  public details?: Record<string, any>;

  constructor(statusCode: number, message: string, details?: Record<string, any>) {
    super(message);
    this.statusCode = statusCode;
    this.details = details;
    // 修复原型链,保证instanceof判断正常工作
    Object.setPrototypeOf(this, CustomError.prototype);
  }
}

// 还可以扩展具体的业务错误类型,比如:
export class NotFoundError extends CustomError {
  constructor(message = "资源未找到", details?: Record<string, any>) {
    super(404, message, details);
  }
}

export class ValidationError extends CustomError {
  constructor(message = "参数验证失败", details?: Record<string, any>) {
    super(400, message, details);
  }
}

第二步:实现全局错误拦截器

routing-controllers提供了@ErrorHandler()装饰器,用来定义全局错误处理类。我们用它来捕获所有未处理的错误(包括控制器里被拒绝的Promise):

import { ErrorHandler, KoaErrorMiddlewareInterface, HttpError } from "routing-controllers";
import { Context } from "koa"; // 用Koa的话用这个类型,Express的话换成对应的Request/Response
import { CustomError } from "./CustomError";

@ErrorHandler()
export class CustomErrorHandler implements KoaErrorMiddlewareInterface {
  async error(error: any, ctx: Context) {
    // 优先处理我们自定义的错误
    if (error instanceof CustomError) {
      ctx.status = error.statusCode;
      ctx.body = {
        success: false,
        message: error.message,
        details: error.details || null,
        timestamp: new Date().toISOString()
      };
      return;
    }

    // 处理routing-controllers自带的HttpError(比如路由不存在、方法不允许等)
    if (error instanceof HttpError) {
      ctx.status = error.httpCode;
      ctx.body = {
        success: false,
        message: error.message || "服务器错误",
        details: null,
        timestamp: new Date().toISOString()
      };
      return;
    }

    // 处理其他未知错误(比如Promise拒绝但没抛出自定义错误)
    console.error("服务器未知错误:", error); // 服务器端打日志方便排查,不要返回给前端
    ctx.status = 500;
    ctx.body = {
      success: false,
      message: "服务器内部错误",
      details: null,
      timestamp: new Date().toISOString()
    };
  }
}

如果是用Express的话,只需要把KoaErrorMiddlewareInterface换成ExpressErrorMiddlewareInterface,参数换成request、response、next即可,核心逻辑完全一致。

第三步:注册错误处理器到routing-controllers

初始化routing-controllers的时候,一定要把我们的错误处理器加进去,同时关闭默认错误处理:

import { createKoaServer } from "routing-controllers";
import { CustomErrorHandler } from "./CustomErrorHandler";
import { UserController } from "./controllers/UserController";

const app = createKoaServer({
  controllers: [UserController], // 你的控制器列表
  errorHandler: CustomErrorHandler, // 注册自定义错误处理器
  defaultErrorHandler: false, // 关闭默认错误处理,完全用我们自己的逻辑
});

app.listen(3000, () => {
  console.log("服务器启动在3000端口");
});

第四步:在控制器中使用自定义错误

现在不管你在控制器里是同步抛错,还是异步Promise被拒绝,都会被我们的处理器捕获并返回自定义响应:

import { Controller, Get, Param } from "routing-controllers";
import { NotFoundError } from "./CustomError";
import { UserService } from "../services/UserService";

@Controller("/users")
export class UserController {
  constructor(private userService: UserService) {}

  @Get("/:id")
  async getUser(@Param("id") id: string) {
    const user = await this.userService.getUserById(id);
    if (!user) {
      // 抛出自定义404错误,携带额外信息
      throw new NotFoundError(`ID为${id}的用户不存在`, { userId: id });
    }
    return { success: true, data: user };
  }

  @Get("/test-error")
  async testPromiseReject() {
    // 模拟Promise被拒绝的场景,会被错误处理器捕获
    await Promise.reject(new ValidationError("参数格式错误", { param: "test" }));
  }
}

核心要点说明

  • 全覆盖捕获:不管是控制器里同步抛出的错误,还是异步函数中被拒绝的Promise,这个处理器都能完美捕获,因为routing-controllers会自动处理异步函数的Promise结果。
  • 自定义响应体:响应体的格式完全由你掌控,比如success、message、details这些字段都可以根据业务需求调整。
  • 关闭默认处理:defaultErrorHandler: false确保不会触发Koa的默认错误处理,不会把堆栈跟踪这类敏感信息返回给前端。
  • 日志留存:对于未知错误,我们在服务器端保留日志方便排查,但返回给用户的是友好的通用提示,兼顾调试和用户体验。

内容的提问来源于stack exchange,提问作者peterschrott

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:48:18