如何使用promise在express.js中正确处理错误(string或对象)

我不是在我的第一个express.js应用程序,但我仍然找出最强大的方法来处理错误。

由于io.js是几个月的现实,我使用原生Promise来帮助自己asynchronous,下面的代码反映了这一点。

我的error handling中间件如下:

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 }; 

正如你所看到的快递中间件看起来相当整齐和优雅。
我通常在rejects()把所有有趣的error handling给用户,其中一些被我们告诉error handling中间件的对象调用。

问题是来自示例的service是第三方库。 这些库有时会返回一个string,有时候是一个对象(来自外部的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) 

这并不酷,我真的很想找出一种方法来处理这些错误,而不添加代码(如果可能的话),因为我觉得这个语法非常优雅和简洁。

我想了很多关于这个问题,我最终创build/使用这个https://github.com/yzarubin/x-error/blob/master/lib/x-error.js这是一个自定义的服务器端错误对象,inheritance错误,并扩展function来处理http代码和响应&#x3002;

把它应用到你的案例中,我会这样做:

 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'); });