2016-12-25 153 views
0

我对节点的req, res参数有点困惑,并且在我使用异步调用时处理这些参数的最佳方式。我目前拥有的一个功能应该是将一个Item添加到我的数据库中,相应地更新一些数据库模型,然后发送一个响应,说明更新已成功。但是,如果发生错误,该函数异步调用的函数可能会发送错误的响应。如果发生这种情况,我会收到错误Can't set headers after they are sent,因为我正在尝试拨打res.send两次。希望得到某人的帮助,找出更好的处理错误的方法。谢谢!如何处理错误,而无需在node.js中设置res头两次

主要功能:

item.author = req.user._id; 
item.description = req.query.description; 
item.rating = req.query.rating; 

item.save() 
    .then(result => { 
     // update user's items 
     UserController.updateItems(req.user._id, result._id); 
     ItemController.updateItemRating(req.query.outingId, req.query.rating, res); 
     res.send(result); 
    }) 
    .catch(error => { 
     res.send(error); 
    }); 

updateItemRating:

export const updateItemRating = (itemId, rating, res) => { 
    Item.findOne({ _id: itemId }).exec((err, item) => { 
     if (item === undefined || item === null) { 
      return res.status(404).send('Item not found; check item ID'); 
     } 

     Item.findOneAndUpdate(
      { _id: itemId }, 
      { $set: { rating: rating }, 
      }, 
      (error, item) => { 
       if (error) { 
        res.status(404).send('Error updating item with new rating'); 
       } 
      }); 
    }); 
}; 

updateItems:

export const updateItems = (userId, itemId) => { 
    User.findOneAndUpdate(
     { _id: userId }, 
     { $push: { items: [itemId] } }, 
     (err, user) => { 
      console.log('user' + user); 
      if (err) { 
       console.log('got an error in updateItems'); 
      } 
     }); 
}; 
+0

您试图执行'updateItemRating'作为同步功能,而是**异步**功能。你应该链接承诺,然后最后使用一个'res.send'。或者使用**异步/等待** – Hosar

回答

2

函数调用到updateItemsupdateItemRating都是异步的。响应发送被称为多个时间,也不知道哪个方法发送首先被调用。要解决你的问题,我可以建议你申请以下技术:

  1. 回调:您可以将回调作为参数,它会做res.send和相同的回调,你可以在错误或成功的条件调用。

    UserController.updateItems(req.user._id, result._id,function(status,message){res.status(status).send(message);});

您可以更新项目的评价方法,如:

export const updateItemRating = (itemId, rating, callback) => { 
    Item.findOne({ _id: itemId }).exec((err, item) => { 
     if (item === undefined || item === null) { 
      callback(404,'Item not found; check item ID');  
     }  
     Item.findOneAndUpdate(
      { _id: itemId }, 
      { $set: { rating: rating }, 
      }, 
      (error, item) => { 
       if (error) { 
        callback(404,'Error updating item with new rating'); 
       }else{ 
        callback(200); 
       } 
      }); 
    }); 
}; 
  • Async Module:您可以使用此模块同步你的方法调用。
  • +0

    谢谢!我最终使用Async'series'并按照您的建议应用了回调,现在它可以工作。 – user3802348

    0

    而不是让您的更新功能将结果发送,您应该抛出()错误,那样你的外部函数就会捕获错误,你可以用它来返回它。

    另一种考虑这种情况的方法是你的外部函数用res.send()处理成功案例,所以它也应该对错误情况的res.send负责。

    数据库层知道调用者越少,重用我们的代码就越容易。

    创建自定义错误类型封装404:

    function NotFoundError(message) { 
        this.message = (message || ""); 
    } 
    NotFoundError.prototype = new Error(); 
    

    然后用在你的内部函数:

    export const updateItemRating = (itemId, rating, res) => { 
    Item.findOne({ _id: itemId }).exec((err, item) => { 
        if (item === undefined || item === null) { 
         throw new NotFoundError('Item not found; check item ID'); 
        } 
    
        Item.findOneAndUpdate(
         { _id: itemId }, 
         { $set: { rating: rating }, 
         }, 
         (error, item) => { 
          if (error) { 
           throw new NotFoundError('Error updating item with new rating'); 
          } 
         }); 
        }); 
    }; 
    

    而主要成为:

    item.save() 
    .then(result => { 
        // update user's items 
        UserController.updateItems(req.user._id, result._id); 
        ItemController.updateItemRating(req.query.outingId, req.query.rating, res); 
        res.send(result); 
    }) 
    .catch(error => { 
        if (error instanceof NotFoundError) { 
         res.status(404).send(error.message); 
        } 
        else { 
         res.send(error); 
        } 
    }); 
    
    +0

    我试图按照你的建议实现,但最终得到一个堆栈跟踪开始'错误:找不到项目;检查项目ID。是否有一些问题来捕捉源于Mongoose查询的错误?我不确定发生了什么问题,为什么我不能正确地捕捉错误。 – user3802348

    +0

    我刚刚注意到在我的示例中有一个错字 - 更新为正确 - NotFound.prototype应该是NotFoundError.prototype – kah608

    +0

    是的 - 我实际上已经捕获了该错误,并在我的应用程序中将其更改为NotFoundError,但仍然无法正常工作。它看起来像是成功地抛出了错误(因为堆栈跟踪正在打印),但我从来没有输入catch语句('console.log'这里没有打印任何东西到控制台)。 – user3802348

    相关问题