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

抛出自定义错误类却识别为Error实例而非自定义错误实例

问题描述

我创建了NotFoundError、ConflictError和UnauthorizedError等特定错误类,它们均继承自BaseError,而BaseError又继承自Node.js的Error类。

当抛出这些自定义错误时,我期望错误实例属于对应的自定义错误类。比如执行throw new UnauthorizedError('Missing api-key')时,错误实例应该是UnauthorizedError,但在errorHandler中间件中接收到的错误却变成了Error实例,导致无法按自定义类型返回对应响应。

相关逻辑如下:

error-handler.middleware.ts

export const errorHandler = (error: unknown, req: Request, res: Response, next: NextFunction) => {
    console.log('Instance of', error?.constructor.name);

    if (error instanceof ValidationError) {
        return res.status(error.status).json({ errors: error.errors });
    }

    if (error instanceof UnauthorizedError) {
        return res.status(error.status).send({ error: error.message });
    }

    if (error instanceof BaseError) {
        return res.status(error.status).send({ error: error.message });
    }

    if (error instanceof Error) {
        return res.status(HttpCode.INTERNAL_SERVER_ERROR).json({
            message: 'Internal Server Error',
        });
    }

    next();
};

以下是相关错误类和中间件代码:

base.error.ts

export class BaseError extends Error {
    status: number;
    message: string;

    constructor(status: number, message: string) {
        super(message);

        this.status = status;
        this.message = message;
    }
}

unauthorized.error.ts

import { BaseError } from './base.error';

export class UnauthorizedError extends BaseError {
    message: string;

    constructor(message: string = 'Unauthorized to perform this action') {
        super(HttpCode.UNAUTHORIZED, message);
        this.message = message;
    }
}

api-key-handler.middleware.ts

export const validateApiKey = async (req: Request, res: Response, next: NextFunction) => {
    const code = req.headers['x-api-key'] as string;

    if (!code) {
        throw new UnauthorizedError('Missing api-key');
    }

    next();
};

问题原因与解决方案

问题出在自定义Error类没有正确设置原型链。在TypeScript/JavaScript中继承内置Error类时,默认的原型链会被破坏,导致instanceof判断失效,错误实例会被识别为原生Error而非自定义类。

解决方案:修正BaseError的原型链

修改base.error.ts,在构造函数中添加原型链修正代码:

export class BaseError extends Error {
    status: number;
    message: string;

    constructor(status: number, message: string) {
        super(message);

        // 修正原型链,确保instanceof判断正确
        Object.setPrototypeOf(this, BaseError.prototype);
        
        this.status = status;
        this.message = message;
        // 可选:保留原生Error的栈追踪信息
        Error.captureStackTrace(this, this.constructor);
    }
}

关键说明

  • 调用super()时,JavaScript会默认将实例原型指向Error.prototype,而非自定义类的原型,这直接导致instanceof判断失败。
  • Object.setPrototypeOf(this, BaseError.prototype)手动将实例原型指向自定义类的原型,恢复正确的继承关系。
  • Error.captureStackTrace是可选操作,用于保留错误栈信息,和原生Error的行为保持一致。

额外提示

只要BaseError正确设置了原型链,所有继承它的子类(如UnauthorizedError)都会自动继承正确的原型链,无需在子类中重复操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 02:20:20