简体   繁体   English

NodeJS最佳实践:流量控制的错误?

[英]NodeJS best practices: Errors for flow control?

In Node.js, should I use errors for flow control, or should I use them more like exceptions? 在Node.js中,我应该使用错误进行流量控制,还是应该像异常一样使用它们?

I'm writing an authentication controller and some unit tests in Sails.js, and currently, my registration method checks to see if a user with the same username exists. 我正在Sails.js中编写一个身份验证控制器和一些单元测试,目前,我的注册方法检查是否存在具有相同用户名的用户。 If a user already exists with the username, my model method calls its callback arguments with a new Error object, like so: 如果用户已经存在用户名,我的模型方法会使用新的Error对象调用其回调参数,如下所示:

Model: 模型:

exists: function (options, cb) {
    User.findOne({
        where: { username: typeof options === 'Object' && options.username ? options.username : options },
    }).exec(function (err, user) {
        if (err) return cb(err);
        if (user) return cb(new Error("A user with that username already exists."));
        cb(null, !!user);
    });
},

Controller: 控制器:

User.exists(req.body.user.username, function (err, exists) {
  if (err) {
    console.log("error: ", err);
    return res.status(409).json({
      message: err
    });      
  }

  User.create(req.user).then(function (data) {
    res.status(201).json({
      user: data
    });
  });
});

Is this best practice? 这是最佳做法吗? I'm not sure if node conventions favor errors for exceptional cases, or for flow control. 我不确定节点约定是否支持异常情况或流量控制的错误。 I'm thinking I should rewrite this, but I want to know conventions before I do so. 我想我应该改写这个,但是在我这样做之前我想知道惯例。 I think I've seen some examples written this way in Sails. 我想我已经在Sails中看到过这样写的一些例子。 Thanks! 谢谢!

Node (or Javascript really) can throw errors on exceptions by using the keyword throw : 通过使用关键字throw Node(或Javascript)可以在异常上抛出错误:

if (something_went_wrong) {
  throw new Error('Doh!');
}

You can also add additional parameters to the default Error object to give more semantic meaning to your errors in your program. 您还可以向默认的Error对象添加其他参数,以便为程序中的错误提供更多语义含义。 With that said, you wouldn't want to throw an error in your route handler because this would crash the process and your server. 话虽如此,您不希望在路由处理程序中抛出错误,因为这会使进程和服务器崩溃。

When using route handlers in Sails (or express really), you most certainly should check the type of error and respond to the client accordingly. 在Sails中使用路由处理程序(或真正表达)时,您当然应该检查错误类型并相应地响应客户端。

// -- Route handler
app.get('/something', function (req, res, next) {

  DB.create({ username: 'user' }, function (err, docs) {

    if (err) {

      // This checks to see if we have a unique error from MongoDB
      // and send the appropriate response to the client
      if (err.code === 11000 || error.code === 11001) {
        return res.send(409); // or return res.json(409, {message: "User exists"});
      }

      // Any other error type is assumed to be an internal error so we pass it
      // down the chain to the error handler middleware
      return next(err);

    }

    // This is a client error, not an internal error so we respond to the client
    // with the appropriate client error type
    if (docs.length === 0) return res.send(404);

    if (user.notAuthorized) return res.send(403);

    res.send('All Good');

  });

});

Notice that in the case that the DB responds with an internal error, we pass to the next() function which is picked up by error handling middleware down the chain. 请注意,在DB响应内部错误的情况下,我们将传递给next()函数,该函数由链中的错误处理中间件拾取。 Any middleware with an arrity of 4 is defined as error handling middleware. 任何精度为4的中间件都被定义为错误处理中间件。 Sails probably has some default error handler, but you can probably also override it — you'll need to check the appropriate docs for this information as I prefer the control I gain by using Express alone. Sails可能有一些默认的错误处理程序,但您也可以覆盖它 - 您需要检查相应的文档以获取此信息,因为我更喜欢单独使用Express获得的控件。

The above answer is good for Express, but in Sails controllers you should not be calling next ; 以上答案适用于Express,但在Sails控制器中你不应该打电话给next ; best practice is to always return a response. 最佳做法是始终返回响应。 In most example Sails code you won't even see next as an argument to a controller action function. 在大多数示例Sails代码中,您甚至不会将next作为控制器动作函数的参数。 Also note that Sails comes with some default response methods built right into the res object, such as res.serverError and res.badRequest , as well as res.negotiate which will attempt to route the error to the appropriate handler for you based on the status code. 另请注意,Sails附带了一些内置于res对象的默认响应方法 ,例如res.serverErrorres.badRequest ,以及res.negotiate ,它将根据状态尝试将错误路由到适当的处理程序码。 So your example could be tweaked as: 所以你的例子可以调整为:

Model: 模型:

exists: function (options, cb) {
    User.findOne({
        where: { username: typeof options === 'Object' && options.username ? options.username : options },
    }).exec(function (err, user) {
        // res.negotiate will default to a 500 server error
        if (err) return cb(err);
        // res.negotiate will just output the status code and error object
        // as JSON for codes between 400 and 500, unless you 
        // provide a custom view as api/responses/badRequest.ejs
        if (user) return cb({
          status: 409, 
          message: "A user with that username already exists."
        });
        cb(null, !!user);
    });
},

Controller: 控制器:

User.exists(req.body.user.username, function (err, exists) {
  // Let Sails handle those errors for you
  if (err) {return res.negotiate(err);}

  User.create(req.user).then(function (data) {
    res.status(201).json({
      user: data
    });
  });
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM