在javascript中处理两层之间的错误

时间:2014-04-20 09:52:54

标签: javascript node.js error-handling

我有一个node.js app使用express和3层(控制器,api和模型)。

控制器要求API层发布,编辑或添加对象(承诺样式)。 API验证并执行请求(使用模型层(mongoose))。控制器必须通过呈现错误页面或flash消息告诉客户端他的请求是否已被接受。 这是一个显示主要结构的小图表。

app structure chart

以下是一个例子:

Controller:

  exports.doEdit = function(req, res) {
    var args;
    args = req.body;
    return app.api.mods.edit(req.getUserId(), req.params.id, args.name, args.value).then(function(status) {
      return res.send(200, "Saved!");
    }).fail(function(err) {
      return res.send(400, err.message);
    });
  };

API Layer:

/*
  Edit a mod
  @param userid the current logged user id 
  @param slug the slug of the mod
  @param field the field to be edited
  @param value the new value
  @permission mod:edit
  */


  exports.edit = (function(userid, slug, field, value, callback) {
    return canThis(userid, "mod", "browse").then(function(can) {
      var Mod;
      Mod = mongoose.model("Mod");
      return Mod.findOne({
        slug: slug
      }, function(err, mod) {
        if (can === false && mod._id !== userid) {
          return callback(new Error("unauthorized"));
        }
        if (err || !mod) {
          if (err) {
            console.log(err);
          }
          return callback(new Error("Please try again"));
        }
        mod[field] = value;
        mod.save();
        return callback("ok");
      });
    });
  }).toPromise(this);

如何轻松,灵活,清晰地沟通错误?

我想过添加像这样的JSON对象

{
    status: "error",
    code: "404",
    id: "not_found",
    message: "Not found"
}

但是如何将其添加到仅包含消息的错误中?它是否灵活且干净"?

整个项目可以在这里看到:https://github.com/CraftYourModCorporation/OpenCubes

1 个答案:

答案 0 :(得分:1)

如果我理解你的话,你会询问如何使用足够的信息将错误传播给客户端。

首先,javascript是动态的,因此您可以在将其传递给回调/响应之前将所需的属性添加到Error实例中。

    if (can === false && mod._id !== userid) {
      var error = new Error("unauthorized")
      error.code = 401
      error.id = "not_authorized"
      return callback(error);
    }

不要忘记,在关注点分离的问题上,每一层都有自己的语义,并且必须封装较低层。对于错误处理也是如此。有时候让错误冒出来是合适的,但在大多数情况下,这是不好的,或者至少是糟糕的用户体验。因此,至少在Controller中,您应该将此处冒出的任何错误转换为用户/客户端友好的http错误代码。为此,您必须考虑错误对上一层的意义。

所以像res.send(404, err.message)这样的代码很简单,但不是很有帮助。如果你真的想要做一个好的错误处理,那么你必须更进一步,并在这里做一些匹配。在像Java这样的静态类型语言中,您可以在Type上进行匹配。对于JS,这也是可能的(使用instanceof),但这不是很可靠。但是你可以使用其他所有属性或者使用定义良好的错误类型引入自己的属性。

    var error = new Error("Some lengthy message for humans, who are reading log files")
    error.errType = require('./errorTypes').NOT_AUTORIZED
    callback(error)

并在api用户代码中

    if(err){
        if(err.errType === errorTypes.NOT_AUTHORIZED)
           return res.send(401, "Wrong credentials")        
    }

你可以减少代码重复,将错误匹配提取到自己的模块或简单的函数中,将内部类型映射到外部。

所以这很简单(不一样简单,容易取决于你的上下文),并且它在回调样式代码意义上是干净的。同样适用于基于promise的apis,只有你有错误传播和解析和拒绝控制流的分离。

我没有涉及的是Node.js域名(因为它们不易于使用快递)和Zone.js。这可能会带来另一个用于错误处理的工具链,但实质上它仍然是相同的。你必须在某处改变错误。