2014-09-18 17 views
1

我的服務器死機了,我發現我的日誌以下錯誤:節點,快速,案例研究:「錯誤:無法設置頭後,他們被送到」

Error: Can't set headers after they are sent. 

,我無法重現錯誤。我想我找到了一個修復程序,但我想確保我理解下面代碼中概述的問題。基於this post,我相信它是從多個進來我的快遞路由器res.send(..)電話:

router.post('/adduser', function(req, res) { 
    var msg = '(message okay)' 
    var db = req.db;  
    db.collection('userlist').find({ 
     username: req.body.username; 
    }).toArray(function(err, items) { 

     // verify the user, set session fields, etc... 

     console.log("message after user verification is: "); 
     console.log(msg); 

     res.send({ 
      msg: msg 
     }); 

    }); 

    // Insert the request's data into the 'userlist' collection. 
    db.collection('userlist').insert(body, function(err, result) { 
     console.log("inserting into userlist..."); 
     res.send(
      (err === null) ? { 
       msg: msg 
      } : { 
       msg: err 
      } 
     ); 
    }); 
    console.log("message after user verification is: "); 
    console.log(msg); 
} 

最後我日誌的幾行:

message after user verification is: 
(message okay) 
POST /login/adduser 200 7ms - 10b 
inserting into userlist... 

/home/lucas/mynode/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/c 
onnection/base.js:245 
     throw message;  
      ^

Error: Can't set headers after they are sent. 
at ServerResponse.OutgoingMessage.setHeader (http.js:689:11) 
at ServerResponse.header (/home/lucas/mynode/node_modules/express/lib/response.js:717:10) 
at ServerResponse.send 

我懷疑我打電話了res.send(..)兩次,所以我相信我通過刪除第一個res.send(..)來解決這個問題,但這是否正確?另外,如果調用res.send(..)兩次會導致錯誤,那麼爲什麼我不能重現此錯誤?我從來沒有得到這個錯誤,但另一個用戶做到了。

任何人都可以提供解釋嗎?對我的解決方案的反饋也會非常有幫助。

+2

是的,這是由於'res.send()'的多次使用。 Express''res.send()'通過['res.end()'](http://nodejs.org/api/http.html#http_response_end_data_encoding)完成對Web客戶端的響應。一旦響應結束,直到一個新的'req'用它自己的'res'到達,才能/不能寫入更多的輸出。 – 2014-09-18 20:50:00

+1

請注意,它看起來像你也可能有兩個異步操作之間的競爭條件,並沒有秩序的保證。如果你想確保第二個數據庫操作發生在第一個數據庫之後,那麼你需要手動對它們進行排序,直到第一個數據庫完成,或者不插入第二個結果直到第一個結果爲止完成。 – jfriend00 2014-09-18 20:58:50

+0

最近我也遇到了同樣的問題。我曾使用res.set(「連接」,「關閉」);在res.json()之後......那就是問題所在。我刪除了res.set和wolla,它的工作很棒。 – 2014-12-12 07:20:12

回答

3

你應該調整你的代碼,自動取款機,你得在你的代碼2異步調用

db.collection('userlist').find is called and will return later 
db.collection('userlist').insert and will also return later 

所以你打電話res.send 2倍

這樣的事情,你會不會調用資源。發送兩次

router.post('/adduser', function(req, res) { 
    var msg = '(message okay)' 
    var db = req.db; 

    db.collection('userlist').find({username: req.body.username}).toArray(function(err, items) { 
    // verify the user, set session fields, etc... 
    // if error return(send) error 
    if(err) return res.send({err:"errormessage"}) 
    // if everything is ok - Insert the request's data into the 'userlist' collection. 
    db.collection('userlist').insert(body, function(err, result) { 
     //if error return(send) error 
     if(err) return res.send({err:err}) 
     //everything was ok send msg 
     res.send({msg:msg}) 
    }) 
    }) 
2

一下你對這個問題的原因正確然而,沒有足夠的信息,在這裏,以確定是否日e解決方案是正確的。

例如,與find/insert調用之間的示例沒有明顯的關係 - 是否應該將這些調用串聯調用? insert是否需要find?例如,如果您需要檢查記錄是否存在插入,那麼正確的解決方案看起來像

db.collection('userlist').findOne({ 
    username: req.body.username 
}, function(err, result) { 
    if (result !== null) { 
     db.collection('userlist').update(result, body, function(err, updateCount) { 
      if (err !== null) { 
       console.log('Updated existing record'); 
      } 
     }); 
    } else { 
     db.collection('userlist').insert(body, function(err, result) { 
      if (err !== null) { 
       console.log('Created new record'); 
      } 
     }); 
    } 
}); 

注意這裏的區別? 請記住,findinsert分別是非阻塞在您的示例中調用您無法保證兩個回調的運行順序。但是,通過將insert呼叫轉入find回撥,我們保證在find之後insert將始終被稱爲

相關問題