先看一个简单的示例:
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(); }); }};
优雅的错误处理是系统可维护性的重要组成部分,它和代码各部分息息相关,系统成型后很难再引入错误处理,设计系统时应该一开始就将它纳入考虑范围。
参考
《Error Handling in Nodejs - Developer Center - Joyent》
来自Joyent的Node.js错误处理最佳实践
-
派生Error类注意事项
《What is the error object? - docs.nodejitsu.com》
Error对象详解
《Creating Custom Error Objects In Node.js With Error.captureStackTrace()》
直接可用的自定义Error类方案
-
用于扩展Error类的node.js模块
-
包裹原始Error对象,并且保证可访问性的node.js模块,Joyent的Node.js错误处理最佳实践中进行了推荐
《Support for custom error types? · Issue #15 · davepacheco/node-verror》
node-verror 支持扩展的讨论