2016-12-25 155 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

    相關問題