如何使用NodeJS / Express处理和返回API中的错误

时间:2016-01-30 10:12:02

标签: node.js api express error-handling

我使用NodeJS创建一个API,使用快速框架和mongodb来存储我的数据。

我有一个寄存器功能,可以做三件事。

  1. 创建新的。
  2. 创建令牌并将其与用户关联。
  3. 发送电子邮件。

    module.exports.register = function(req,res){

    var input = req.body;
    var token = uuid.v4();
    
    
    // Create a new user
    var user = new User ({
    
        username: input.username,
        email: input.email,
        password: input.password,
        active: false
    
    });
    
    user.save(function(err) {
    
        if(err) return res.json({success: false, errors: 'Failed To Create User'});
    
    });
    
    
    // Create a new Token
    var newToken = createToken('new', null, user._id);
    
    
    // Assign New Token To New User
    if(newToken) {
    
    
        user.tokens.push(newToken._id);
    
    
        user.save(function(err) {
    
            if(err) return res.json({success: false, errors: 'Failed To Save User Token'});
    
        });
    
    }
    
    
    // Send Email To User
    var mailData = {
    
        from: 'deleted@hotmail.com',
        to: input.email,
        subject: 'Activate Your Account',
        text: 'http://localhost:8080/api/auth/activate/' + token
    
    }
    
    mail.messages().send(mailData, function(err, body) {
    
        if(err) return res.json({ success: false, errors: 'Failed To Send Email' });
    
    });
    
    
    return res.json({ 
        success: true, 
        status: 'Successfully Registered User, Check Email To Activate' 
    });
    

    }

  4. 现在即使在创建用户或令牌或发送电子邮件时出现错误。它总是会返回它成功注册用户。我怎样才能更好地重组/处理这个?

    我还有一个问题,如果电子邮件无法发送用户并且已经创建了令牌,我该如何解决这个问题?我会创建重发激活功能吗?

2 个答案:

答案 0 :(得分:1)

您提到它总是会返回它已成功注册用户。即使令牌创建失败,它也会发送电子邮件。

一种(不是很漂亮)的方法是继续上一步回调函数中的下一步:

user.save(function(err) {
  if(err) {
    return res.json({success: false, errors: 'Failed To Create User'});
  } else {
    // Create a new Token
    var newToken = createToken('new', null, user._id);
    // Assign New Token To New User
    if(newToken) {
      user.tokens.push(newToken._id);
      user.save(function(err) {
        if(err) {
          return res.json({success: false, errors: 'Failed To Save User Token'});
        } else {
          // Send Email To User
          var mailData = {
            from: 'deleted@example.com',
            to: input.email,
            subject: 'Activate Your Account',
            text: 'http://localhost:8080/api/auth/activate/' + token
          }

          mail.messages().send(mailData, function(err, body) {
            if(err) {
              return res.json({ success: false, errors: 'Failed To Send Email' });
            } else {
              return res.json({ 
                success: true, 
                status: 'Successfully Registered User, Check Email To Activate' 
              });                
            }
          });
        }
      });
    }
  }
});

正如您所看到的,它看起来像一个非常快速的回调-piramyd-of-doom,但它只在完成所有前面的步骤后发送成功响应。

您还应该在未创建newToken时添加else案例。

答案 1 :(得分:0)

如果没有错误,你应该删除final return语句(从你的代码末尾开始)并返回每个回调内的正确位置。

如果您在函数正文中发送响应,则回调将永远无法运行。因此,您必须嵌套回调,并且只有在

时才调用res.send
  • 由于错误或
  • 提早返回
  • 如果一切都完整。

e.g。

// Create a new user
var user = new User ({
    username: input.username,
    email: input.email,
    password: input.password,
    active: false
});

user.save(function(err) {
    if(err) return res.json({success: false, errors: 'Failed To Create User'});

    // Create a new Token
    var newToken = createToken('new', null, user._id);
    // Assign New Token To New User
    if(newToken) {
        user.tokens.push(newToken._id);
        user.save(function(err) {
            if(err) return res.json({success: false, errors: 'Failed To Save User Token'});

            // Send Email To User
            var mailData = {
                from: 'deleted@hotmail.com',
                to: input.email,
                subject: 'Activate Your Account',
                text: 'http://localhost:8080/api/auth/activate/' + token
            }

            mail.messages().send(mailData, function(err, body) {
                if(err) return res.json({ success: false, errors: 'Failed To Send Email' });

                return res.json({
                    success: true,
                    status: 'Successfully Registered User, Check Email To Activate'
                });
            });
        });
    }
});

异步替代

不幸的是,对于node.js,你应该习惯并理解回调;即使你最终在大部分时间都使用其他东西。您的代码的结构方式更整洁,但在node.js中不起作用,因为您必须等待回调完成才能从函数返回

但是,回调是默认值,但却是处理异步逻辑的最糟糕机制之一。如果您想以不同的方式构建代码,那么您有很多选择。这里只是一对:

  1. 使用promises而不是回调。
  2. 在您的情况下,您的数据库库(mongoose?sequelize?)应该内置一些允许您编写代码的内容:

    user.save()
      .then(function () {
          // step 1
      })
      .then(funciton () {
          // step 2
      })
      .done()
    

    这种编程风格非常值得学习,它将使您的代码比回调更具可读性。 callbacks vs promises

    1. 使用Koa代替express。
    2. Koa,是由同一个人写的下一代快递。它使用生成器而不是回调,这意味着您可以编写看起来更像这样的代码:

      // this is just an example
      var result = user.save();
      if (result.error) return res.send({success : false, ...});
      
      user.token = getNewToken();
      user.update();
      if (result.error) return res.send({success : false, ...});    
      
      return res.send({success : true, message : "Good news, no errors"});
      

      生成器/(又称异步函数)是Javascript移动的方向,但是有一个学习曲线可以开始使用。在幕后,有一些非常复杂的事情要使异步代码看起来像同步代码。基本上,这些函数知道如何暂停执行,直到再次需要它们为止。

      从回调开始

      就像我说的那样,回调并不是那么好。但是,您应该习惯使用它们。它们是node.js的基本构建块,需要一段时间才能获得更好的替代方案。习惯它们也很重要,否则你不会理解为什么替代品更好。

      祝你好运并注意循环中的回调:)