我正在使用native MongoDB driver for Node.js,而我正试图找到一种方法来捕捉API回调中可能发生的异常。
我知道最佳做法是将代码包装在try-catch块中,但在我的特定情况下,我向用户公开了驱动程序的API,因此我没有那种控制级别。不过,我需要捕捉回调中发生的潜在异常,以便发回相关的错误消息。
编辑:进一步解释。
想想一些"后端即服务"用户可以在Node中创建在服务器上运行的JS代码。用户代码可以直接访问db
对象(来自驱动程序),并且可以随意使用它,例如编写以下内容:
db.collection('test').findOne({ field: 'value' }, function(err, doc){
throw new Error;
});
我需要以某种方式捕捉到这一点,但process.on('uncaughtException')
对我来说太低了。该用户代码是从API请求执行的,因此我想在其响应中返回相关的错误消息。
到目前为止,我已经尝试向.on('error')
对象添加错误处理程序(db
),但它并没有捕获任何内容。任何帮助将不胜感激。
谢谢!
答案 0 :(得分:4)
来自MongoDB驱动程序API的任何错误都将作为第一个参数传递给回调。在try / catch中包含调用不会对您有所帮助,因为错误是异步发生的。换句话说,对MongoDB API的所有调用都是开始异步操作,传入一个回调,以便在异步操作完成后调用(数据库调用返回)。如果在异步操作期间发生错误,您将无法通过try / catch捕获它。只有库本身才能捕获这些错误,这就是库确保将它们作为第一个参数传递给回调的原因。
collection.update({ a : 2 }, { $set: { b : 1 } }, function(err, result) {
if (err) { /* do error handling */ return; }
/* err is null, continue as normal */
});
如果我正在编写自己的API来包含其中一些调用,我可以使用以下三种方法之一。
如果我公开的API是一个回调式API,就像MongoDB驱动程序一样,那么我就是这样做的。
exports.coolFunction = function (callback) {
collection.update({ a : 2 }, { $set: { b : 1 } }, function (err, result) {
if (err) { callback(err); return; }
callback(null, result);
};
然后有人可以像这样使用我的API:
var alexLib = require('alexLibExample');
alexLib.coolFunction(function (err, result) {
if (err) { /* consumer handles error how they want to in their app */ }
/* all is good, no errors, continue normally */
});
或者我可以将我的API设为启用许可的API。
var Promise = require('bluebird');
exports.coolFunction = function () {
return new Promise(function (resolve, reject) {
collection.update({ a : 2 }, { $set: { b : 1 } }, function (err, result) {
if (err) { reject(err); return; }
resolve(result);
});
};
};
然后有人可以使用我支持Prom的API:
var alexLib = require('alexLibExample');
alexLib.coolFunction().then(function (result) {
/* do stuff with result */
}).catch(function (err) {
/* handle error how user chooses in their app */
});
或者我可以将错误作为错误事件发出,这似乎更像是你所追求的。
var EventEmitter = require('events').EventEmitter;
exports.eventEmitter = new EventEmitter();
exports.coolFunction = function (callback) {
collection.update({ a : 2 }, { $set: { b : 1 } }, function (err, result) {
if (err) { exports.eventEmitter.emit('error', err); return; }
callback(result);
});
};
然后有人可以像我这样使用我的事件式API:
var alexLib = require('alexLibExample');
alexLib.eventEmitter.on('error', function (err) {
/* user handles error how they choose */
});
alexLib.coolFunction(function (result) {
/* do stuff with result */
});
API的事件样式通常与回调样式结合使用。这意味着他们仍然将错误传递给回调函数,这是大多数用户在传递回调时所期望的。然后,它们还会发出错误事件,作为用户可以订阅的一种全局错误处理程序。我知道这是Mongoose的工作方式。我可以捕获各个API调用的错误,或者我可以设置错误事件处理程序并处理那里的所有错误。
var EventEmitter = require('events').EventEmitter;
exports.eventEmitter = new EventEmitter();
exports.coolFunction = function (callback) {
collection.update({ a : 2 }, { $set: { b : 1 } }, function (err, result) {
if (err) { exports.eventEmitter.emit('error', err); callback(err); return; }
callback(null, result);
});
};
然后,用户可以灵活处理错误。
var alexLib = require('alexLibExample');
alexLib.eventEmitter.on('error', function (err) {
/* handle all errors here */
});
alexLib.coolFunction(function (err, result) {
if (err) { return; }
/* do stuff with result */
});
alexLib.coolFunction2(function (err, result) {
if (err) { /* maybe I have special error handling for this specific call. I can do that here */ }
/* do stuff with result */
});
如果你真的想要花哨,你可以将这三种风格结合起来。
var EventEmitter = require('events').EventEmitter;
var Promise = require('bluebird');
exports.eventEmitter = new EventEmitter();
exports.coolFunction = function (callback) {
return new Promise(function (resolve, reject) {
collection.update({ a : 2 }, { $set: { b : 1 } }, function(err, result) {
if (err) {
if (callback) { callback(err); }
reject(err);
exports.eventEmitter.emit('error', err);
}
if (callback) { callback(err, result); }
resolve(result);
});
});
};
然后有人可以选择使用我的API。
var alexLib = require('alexLibExample');
alexLib.eventEmitter.on('error', function (err) {
/* handle all errors here */
});
alexLib.coolFunction(function (err, result) {
if (err) {
/* handle this specific error how user chooses */
}
/* do stuff with result */
});
// or
alexLib.coolFunction().then(function (result) {
/* do stuff with result */
}).catch(function (err) {
/* handle any errors in this promise chain */
});
答案 1 :(得分:1)
将此行添加到结尾,,,
process.on('uncaughtException', function (err) {
console.log(err);
});
通过这个,如果底层有任何未捕获的异常,服务器将不会停止。