yarkov
@yarkov
Помог ответ? Отметь решением.

Как правильно наследоваться от объекта Error?

Пытаюсь написать перехват ошибок:
/**
 * A custom APIError class
 * @class
 */
class APIError extends Error {
    /**
     * Constructs the APIError class
     * @param {String} message an error message
     * @param {Number} status=200 HTTP status an error message
     * @param {Number} errcode=0 an error message
     * @constructor
     */
    constructor(message, status=200, errcode=0) {
        super(message);
        this.message = message;
        this.status = status;
        this.errcode = errcode;
        this.name = "APIError";
        this.json = {
            "message": this.message, 
            "status": this.status, 
            "errcode": this.errcode
        };  

        if (Error.captureStackTrace) {
            Error.captureStackTrace(this, this.constructor);
        } else {
            this.stack = (new Error()).stack;
        }
    }
        
    toString() {
        return `[${this.errcode} ${this.name}] ${this.message}`;
    }
    
    toJSON() {
        let json = Object.assign({}, this.json, {name: this.name});
        return json;
    }
}

/**
 * A Error401 class, extends APIError
 * @class
 */
class Error401 extends APIError {
    /**
     * Constructs the Error401 class
     * @param {String} message an error message
     * @constructor
     */
    constructor(message) {
        super(message, 401, 1);
        this.name = "Error401";
    }
}

/**
 * A Error404 class, extends APIError
 * @class
 */
class Error404 extends APIError {
    /**
     * Constructs the Error404 class
     * @param {String} message an error message
     * @constructor
     */
    constructor(message) {
        super(message, 404, 2);
        this.name = "Error404";
    }
}


module.exports.APIError = APIError;
module.exports.Error401 = Error401;
module.exports.Error404 = Error404;

Использую:
var express = require('express');
var app = express();
var router = express.Router();


var errors = require('./errors');

router.get('/401', function ErrEvent(req,res) {
    throw new errors.Error401("Ресурс недоступен!");
    res.send("401");
});

router.get('/404', function ErrEvent(req,res) {
    throw new errors.Error404("Ресурс не найден!");
    res.send("404");
});

app.use('/',router);

app.use(function ErrHandler(err,req,res,next) {
    console.log(err.stack);
    let message = Object.assign({}, err.toJSON(), {error: true});
    res.status(err.status).send(message);
});

app.listen(3000);

Но в консоли пишет: APIError: Ресурс не найден!, а я как бы жду Error404: Ресурс не найден!.
Но в методах toString и toJSON имя правильное.
  • Вопрос задан
  • 229 просмотров
Решения вопроса 1
@amokrushin
В консоль вы выводите не err.toString(), a err.stack, значит вопрос в том откуда берется этот stack
Смотрим
  1. throw new Error404("Ресурс не найден!");
  2. Error404 вызывается конструктор родителя - APIError super(message, 404, 2);
  3. APIError вызывается конструктор родителя - Error super(message);
  4. Конструктор Error. Здесь появляется this.stack - строка которая начинается с Error: Ресурс не найден!

  5. Возвращаемся к конструктору APIError после super(message); Меняется имя this.name = 'APIError'; После этого статический метод Error.captureStackTrace перезаписывает свойство this.stack на сей раз уже используя имя 'APIError', теперь this.stack начинается с APIError: Ресурс не найден!

  6. возвращаемся к конструктору Error404, меняем имя this.name = 'Error404';, но в строке this.stack так и остается APIError: Ресурс не найден!



Исправить можно, например перенеся свойство name в прототип
APIError.prototype.name = 'APIError';
Error404.prototype.name = 'Error404';


Либо удалить
if (Error.captureStackTrace) {
    Error.captureStackTrace(this, this.constructor);
} else {
    this.stack = (new Error()).stack;
}

Похоже на то, что для this.stackError устанавливает геттер затем используется ленивое вычисление, и если его не трогать раньше времени, то получится ожидаемое значение.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы