node.js应用错误处理

先看一个简单的示例:

app.post('/products', function (req, res) {
    service.add(req.body, function (err) {
        if (err) {
            logger.error(err.toString());
            res.statusCode = 500;
            return res.end({error: err.message});
        }

        res.statusCode = 200;
        res.end();
    });
}};

上面的代码能够直接用于产品环境吗?

对于稍微严谨的产品,答案肯定是

针对 service.add 调用失败提两个疑问:

  • 如何根据错误类型给客户端返回不同的响应,以便客户端更人性化(而非简单的弹消息框)?
  • err.message 会不会包含不应该给用户看到的信息?

我们需要规范化错误类型,进行明确的分类标识,直到最外层的代码能够根据错误对象提供的信息,给客户端返回恰当的响应,下面是我能想到的一些基本原则:

  • 错误对象拥有统一的接口

    确保错误对象是一个Error类实例,如需要自定义错误类型,从Error类继承。

  • 对错误进行命名标识

    重量级的做法:为每一个错误类型自定义一个错误类。轻量级的做法:将Error对象的name属性设置为错误类型标识。

  • 在恰当的层次将底层Error对象转化为自定义的错误对象

    对底层返回的原始错误,尽可能在调用栈恰当的层次转化为合适应用层错误对象,但不必强制对所有底层错误进行转换,原生的Error对象可以认为是未标识的错误,这种错误可以默认处理(如:给客户端返回HTTP 500错误)。

错误进行分类标识后的使用示例:

app.post('/products', function (req, res) {
    service.add(req.body, function (err) {
        if (err) {
            logger.error(err.toString());
            if (err.name === 'ProductAlreadyExists') {
                res.statusCode = 400;
            } else {
                err.message = '内部错误';
                res.statusCode = 500;
            }
            return res.end({error: err.message});
        }

        res.statusCode = 200;
        res.end();
    });
}};

优雅的错误处理是系统可维护性的重要组成部分,它和代码各部分息息相关,系统成型后很难再引入错误处理,设计系统时应该一开始就将它纳入考虑范围。

参考


node