如何使用promises正确处理express.js中的错误(字符串OR对象)

时间:2015-02-26 02:13:30

标签: javascript node.js express error-handling robustness

我没有在我的第一个express.js应用程序中,尽管我仍然需要找出最有效的方法来处理错误。

由于io.js在几个月内已成为现实,我使用原生Promise来帮助自己处理异步,以下代码反映了这一点。

我的错误处理中间件如下:

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()中处理用户的所有有趣错误,其中一些错误是通过一个对象调用的,我告诉错误处理中间件。

问题是示例中的service是第三方库。 这些库有时会返回一个字符串,有时是一个对象(来自外部API),有时候是一个javascript错误。

目前我无法处理自定义javascript对象,而且如果我想向用户抛出一个错误500 {}},但有时这个reject(new Error(err));是一个对象,导致:

err

这一点都不酷,我真的想找到一种方法来优雅地处理这些错误,而无需添加代码(如果可能的话),因为我发现这种语法非常优雅和简洁。

1 个答案:

答案 0 :(得分:1)

我已经考虑了很多这个问题,我最终创建/使用了这个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');
});