簡體   English   中英

NodeJS路由-

[英]NodeJS routing -

摘要:

我一次調用下面的代碼,下次調用它時一切都很好,但是在代碼下面得到了錯誤,然后我需要重新啟動服務器才能使其工作,但是再次,它只能工作一次。

注意:

我使用eventEmitter的原因是,如果我用mongoose嵌套兩個數據庫請求,它將先執行父操作,然后執行其子操作,因此我必須確保第一個操作完成才能運行第二個。 但這並不是問題代碼起作用,而只是我第一次運行它時。 以前從未遇到過這個問題,我真的很好奇發生了什么

碼:

// loads people user has chatted with
router.get('/loadUserChats', function(req, res) {
    var hostID = req.query.id;
    let list = [];
    let readyToSend = true;

    // gets photos for each user in the 'list'
    eventEmitter.on('addPictureToObjects', function() {
        list.forEach(function(listItem, i) {
            User.findOne({_id: listItem.id}, 'photo', function(err, guest) {
                listItem.photo = guest.photo;
                // if this is the last one send json object back
                if (i+1 == list.length) {
                    res.json({list: list});
                }
            });
        });
    });

    // get the user
    User.findOne({_id: hostID}, function(err, user) {
        // checks if user has chatted at all
        if (user.chat) {
            // loops through the chat
            user.chat.forEach(function(chat) {
                var photoURL = "";
                console.log(chat.user);
                // push the chat info so later we can load messages
                // by its ID
                list.push({
                    id: chat.user.id,
                    name: chat.user.name
                });
            });
            // okay, now that we are done looping lets add photos
            // to each one of those so it looks better
            eventEmitter.emit('addPictureToObjects');
        }
    });
});

錯誤:

events.js:160
  throw er; // Unhandled 'error' event
  ^

Error: Can't set headers after they are sent.
  at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:344:11)
  at ServerResponse.header (/home/knox97/Documents/agro/node_modules/express/lib/response.js:719:10)
  at ServerResponse.json (/home/knox97/Documents/agro/node_modules/express/lib/response.js:247:10)
  at /home/knox97/Documents/agro/routes/api.js:249:10
  at Query.<anonymous> (/home/knox97/Documents/agro/node_modules/mongoose/lib/model.js:3357:16)
  at /home/knox97/Documents/agro/node_modules/kareem/index.js:259:21
  at /home/knox97/Documents/agro/node_modules/kareem/index.js:127:16
  at _combinedTickCallback (internal/process/next_tick.js:67:7)
  at process._tickCallback (internal/process/next_tick.js:98:9)

我實際上是通過重寫代碼並最初將照片添加到聊天列表對象中來解決此問題的,所以我不必手動添加照片,這是一種更快,更聰明的解決方案,但我真的很好奇為什么這樣做不起作用,喜歡或分享這個問題,所以我們都可以找到答案,加油!

將事件發射器從路由處理程序中拉出。 每次路由處理程序運行時,都會為'addPictureToObjects'添加另一個事件處理程序。 您確實想在每個請求上都發出該事件,但又不想在每個請求上都只注冊一次該事件處理程序。

您收到錯誤消息"Can't set headers after they are sent." 因為第一個事件處理程序運行,所以迭代list所有項目,然后調用res.json將響應發送回客戶端。 但是,由於您為每個請求注冊了多個事件處理程序,因此該代碼將運行兩次該代碼(或三次,四次等,具體取決於您打了那條路線的次數並每次注冊一個新的事件處理程序)。 在該代碼的后續運行中,當第二次進入res.json時,它會錯誤地指出無法再修改響應,因為該響應已經發送回了客戶端。

// gets photos for each user in the 'list'
eventEmitter.on('addPictureToObjects', function(list, res) {
  list.forEach(function(listItem, i) {
    User.findOne({_id: listItem.id}, 'photo', function(err, guest) { 
      listItem.photo = guest.photo;
      // if this is the last one send json object back
      if (i+1 == list.length) {
        res.json({list: list});
      }
    });
  });
});    

// loads people user has chatted with
router.get('/loadUserChats', function(req, res) {
  var hostID = req.query.id;
  let list = [];
  let readyToSend = true;

  // get the user
  User.findOne({_id: hostID}, function(err, user) {
    // checks if user has chatted at all
    if (user.chat) {
      // loops through the chat
      user.chat.forEach(function(chat) {
        var photoURL = "";
        console.log(chat.user);
        // push the chat info so later we can load messages
        // by its ID
        list.push({
          id: chat.user.id,
          name: chat.user.name
        });
      });
      // okay, now that we are done looping lets add photos
      // to each one of those so it looks better
      eventEmitter.emit('addPictureToObjects', list, res);
    }
  });
});

您也可以將eventEmitter.on更改為eventEmitter.once ,這也可以解決您的問題。 .once注冊事件處理程序,但在其運行后注銷。 但是,在您的代碼中似乎毫無意義,因為似乎沒有理由注冊處理程序並在每次請求時一遍又一遍地注銷它,因此在請求處理程序之外注冊事件處理程序似乎是理想的解決方案。


這不是您的實際問題,但是您不需要此處的事件發射器。 它仍然在執行第一個數據庫請求,然后在該請求的回調中發出執行第二個請求的事件。 它仍在執行一個請求,然后執行另一個請求。 事件發射器沒有改變。 以下代碼與上面的代碼等效:

// loads people user has chatted with
router.get('/loadUserChats', function(req, res) {
  var hostID = req.query.id;
  let list = [];
  let readyToSend = true;

  // get the user
  User.findOne({_id: hostID}, function(err, user) {
    // checks if user has chatted at all
    if (user.chat) {
      // loops through the chat
      user.chat.forEach(function(chat) {
        var photoURL = "";
        console.log(chat.user);
        // push the chat info so later we can load messages
        // by its ID
        list.push({
          id: chat.user.id,
          name: chat.user.name
        });
      });
      // okay, now that we are done looping lets add photos
      // to each one of those so it looks better
      list.forEach(function(listItem, i) {
        User.findOne({_id: listItem.id}, 'photo', function(err, guest) { 
          listItem.photo = guest.photo;
          // if this is the last one send json object back
          if (i+1 == list.length) {
            res.json({list: list});
          }
        });
      });
    }
  });
});

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM