如何使用 promises 正确处理 express.js 中的错误(字符串或对象)
How to correctly handle errors (string OR objects) in express.js using promises
我不是第一个 express.js 应用程序,尽管我仍然需要找出处理错误的最可靠方法。
由于 io.js 是几个月后的现实,我使用本机 Promises 来帮助自己处理异步性,以下代码反映了这一点。
我的错误处理中间件如下:
router.use(function (err, req, res, next) {
// in case err.custom is present, means is an "handled" Error, created by developers
if (!!err.custom) {
return res.status(err.code).json(err.message);
}
if (err instanceof Error) {
console.error(err.stack);
return res.status(500).send('Runtime Error'); // should be reported!
}
// last but not least, validation error
res.status(400).send(err);
});
一个例子控制器是这样写的:
function callService1 (param1) {
return new Promise(function (resolve, reject) {
service.call(param1, function (err, data) {
if (!!err) return reject(err); // this is an Error object?? not sure!
if (!!data.handledError) { // this is an handled Error to the user, not 500
return reject({ custom: true, status: 403, message: 'service1 tells you that myCoolParam is not valid' });
}
resolve(data);
});
};
}
function callService2 (dataFromParam1) {
return new Promise(function (resolve, reject) {
// something here
});
}
// this is the API "controller"
module.exports = function (req, res, next) {
callService1(req.body.myCoolParam)
.then(callService2)
.then(function (service2Output) {
res.status(200).json({ message: 'everything went smooth!' });
})
.catch(next); // here is the catch-all errors
};
如您所见,express 中间件看起来非常整洁优雅。
我通常在 rejects()
中为用户处理所有有趣的错误,其中一些是用我告诉错误处理中间件的对象调用的。
示例中的问题 service
是第 3 方库。
这些库有时 returns 一个字符串,有时一个对象(来自外部 API),有时一个 javascript 错误。
目前我无法处理自定义 javascript 对象,此外,如果我想向用户抛出错误 500,我必须做 reject(new Error(err));
但有时这个 err
是一个对象,结果:
Error: [object Object]
at errorHandler (awesomeapi\postsomething.js:123:16)
at IncomingMessage.<anonymous> (node_modules\mandrill-api\mandrill.js:83:24)
at emitNone (events.js:72:20)
at IncomingMessage.emit (events.js:163:7)
at _stream_readable.js:891:16
at process._tickCallback (node.js:337:11)
这一点都不酷,我真的很想找到一种优雅地处理这些错误的方法,而不需要添加代码(如果可能的话),因为我发现这种语法非常优雅和简洁。
关于这个问题我想了很多,最后我得到了 creating/using 这个 https://github.com/yzarubin/x-error/blob/master/lib/x-error.js 它是一个自定义的服务器端错误对象,它继承了 Error,并扩展了处理 http 的功能代码和响应。
要在您的案例中应用它,我会这样做:
function callService1 (param1) {
return new Promise(function (resolve, reject) {
service.call(param1, function (err, data) {
if (!!err) return reject(new xError().extend(err).setHttpCode(500)); // This will inherit the original stack & message
if (!!data.handledError) {
return reject(new xError('this is an handled Error to the user, not 500').setHttpCode(403));
}
resolve(data);
});
};
}
然后在你的控制器中,你可以检查 instanceof xError === true 并处理它,否则做一些默认响应。但是我也在一个应用程序中做了类似的事情,它确定每个承诺最终都会解决或拒绝 xError:
的实例
router.use(function (err, req, res, next) {
res.status(err.httpCode || 500).send(err.message || 'Internal error');
});
我不是第一个 express.js 应用程序,尽管我仍然需要找出处理错误的最可靠方法。
由于 io.js 是几个月后的现实,我使用本机 Promises 来帮助自己处理异步性,以下代码反映了这一点。
我的错误处理中间件如下:
router.use(function (err, req, res, next) {
// in case err.custom is present, means is an "handled" Error, created by developers
if (!!err.custom) {
return res.status(err.code).json(err.message);
}
if (err instanceof Error) {
console.error(err.stack);
return res.status(500).send('Runtime Error'); // should be reported!
}
// last but not least, validation error
res.status(400).send(err);
});
一个例子控制器是这样写的:
function callService1 (param1) {
return new Promise(function (resolve, reject) {
service.call(param1, function (err, data) {
if (!!err) return reject(err); // this is an Error object?? not sure!
if (!!data.handledError) { // this is an handled Error to the user, not 500
return reject({ custom: true, status: 403, message: 'service1 tells you that myCoolParam is not valid' });
}
resolve(data);
});
};
}
function callService2 (dataFromParam1) {
return new Promise(function (resolve, reject) {
// something here
});
}
// this is the API "controller"
module.exports = function (req, res, next) {
callService1(req.body.myCoolParam)
.then(callService2)
.then(function (service2Output) {
res.status(200).json({ message: 'everything went smooth!' });
})
.catch(next); // here is the catch-all errors
};
如您所见,express 中间件看起来非常整洁优雅。
我通常在 rejects()
中为用户处理所有有趣的错误,其中一些是用我告诉错误处理中间件的对象调用的。
示例中的问题 service
是第 3 方库。
这些库有时 returns 一个字符串,有时一个对象(来自外部 API),有时一个 javascript 错误。
目前我无法处理自定义 javascript 对象,此外,如果我想向用户抛出错误 500,我必须做 reject(new Error(err));
但有时这个 err
是一个对象,结果:
Error: [object Object]
at errorHandler (awesomeapi\postsomething.js:123:16)
at IncomingMessage.<anonymous> (node_modules\mandrill-api\mandrill.js:83:24)
at emitNone (events.js:72:20)
at IncomingMessage.emit (events.js:163:7)
at _stream_readable.js:891:16
at process._tickCallback (node.js:337:11)
这一点都不酷,我真的很想找到一种优雅地处理这些错误的方法,而不需要添加代码(如果可能的话),因为我发现这种语法非常优雅和简洁。
关于这个问题我想了很多,最后我得到了 creating/using 这个 https://github.com/yzarubin/x-error/blob/master/lib/x-error.js 它是一个自定义的服务器端错误对象,它继承了 Error,并扩展了处理 http 的功能代码和响应。
要在您的案例中应用它,我会这样做:
function callService1 (param1) {
return new Promise(function (resolve, reject) {
service.call(param1, function (err, data) {
if (!!err) return reject(new xError().extend(err).setHttpCode(500)); // This will inherit the original stack & message
if (!!data.handledError) {
return reject(new xError('this is an handled Error to the user, not 500').setHttpCode(403));
}
resolve(data);
});
};
}
然后在你的控制器中,你可以检查 instanceof xError === true 并处理它,否则做一些默认响应。但是我也在一个应用程序中做了类似的事情,它确定每个承诺最终都会解决或拒绝 xError:
的实例router.use(function (err, req, res, next) {
res.status(err.httpCode || 500).send(err.message || 'Internal error');
});