node.js - 处理不同类型的错误时出错

时间:2015-02-17 13:01:34

标签: node.js express

我正在使用Express编写一系列REST API,并希望编写一种强大而一致的方法来处理错误并将其呈现给用户。到目前为止,我使用的中间件如下所示:

app.use(function(req, res, next){
    res.render('404', { status: 404, error: 'not_found', error_description: 'the url '+req.url+' could not be found' });
});

app.use(function(err, req, res, next) {
    switch (err.name) {
        case 'CastError':
            res.status(400);
            return res.send({code:400, error: 'cast_error', error_description: err});
        default:
            console.log(err);
            return res.send({code:500, error: 'internal_error', error_description: 'something went horribly wrong!'});
    }
});

现在出现的问题是错误可能来自应用程序的任何部分。例如,Mongoose会触发“CastError”之类的错误,可能会出现一般系统错误(无法连接到数据库),还会出现用户验证错误。

现在有些错误我想向用户显示一条消息(例如验证错误或告诉他们API请求有什么问题),而其他人则想要隐藏用户。

所以看一下验证错误:

throw new Error('not a valid project id');

此刻,这只是因为一般性500错误而被捕获,并且没有向用户显示有用的消息。如何将上述错误与一般系统错误区分开来,以便对它们进行不同的处理?是否有我可以使用的错误类型属性(可能是err.name)。如果是这样,我该如何使用它?

概念创意(obv不起作用):

throw new Error('validation', 'not a valid project id');

或者

throw new Error('not a valid project id').name('validation');

2 个答案:

答案 0 :(得分:7)

Error是对象,可以分配其他属性。您可以在构造错误后为错误添加更多属性。另请注意,throw的操作数不必是Error,它可以是任何其他对象。

var validationError = new Error('Not a valid project ID');
validationError.type = 'validation';
throw validationError;

更好的选择是使用从Error继承的自定义错误类。

function ValidationError(message) {
    if(!(this instanceof ValidationError)) {
        return new ValidationError(message);
    }
    var err = this.err = Error.call(this, message);
    this.message = message;

    Object.defineProperty(this, 'stack', {
        get: function () {
            return err.stack; 
        }
    });

}
ValidationError.prototype = Object.create(Error.prototype, {constructor: ValidationError});

此方法可让您使用ValidationError运算符区分instanceof s与其他错误。这是koa应用程序的摘录:

app.use(function *() {
    try {
            if(this.method != 'GET') {
                yield this.connection.beginTransaction();
                yield *next;
                yield this.connection.commit();
            } else {
                yield *next;
            }
        } catch(err) {
            if(err instanceof ValidationError) {
                this.body = err.message;
                this.status = 422;
            } else {
                throw err; //let the framework notify the client of 500 Internal Server errors
            }
            if(this.method != 'GET') {
                yield this.connection.rollback();
            }
        }
});

答案 1 :(得分:4)

您应该考虑使用现有的npm模块,例如http-errorsboom。至少在抛出自己的错误时,这些将使得在响应中获得良好的HTTP语义变得容易。