节点,快速,案例研究:“错误:发送后无法设置标题”
我的服务器崩溃,我在我的日志中发现以下错误:
Error: Can't set headers after they are sent.
我无法重现错误。 我想我find了一个修复程序,但我想确保我理解下面代码中概述的问题。 基于这篇文章 ,我相信它来自我的Express路由器中的多个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(..)
两次导致错误,那么为什么我不能重现这个错误? 我从来没有得到错误,但另一个用户做了。
任何人都可以提供解释吗? 对我的解决scheme的反馈也是非常有帮助的。
你应该重构你的代码,atm你有2个asynchronous调用你的代码
db.collection('userlist').find is called and will return later db.collection('userlist').insert and will also return later
所以你打电话res.send 2次
像这样的事情,你不会调用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... // 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}) }) })
您对问题的原因是正确的,但是,这里没有足够的信息来确定解决scheme是否正确。
例如, find
/ insert
调用之间没有明显的关系 – 这些应该是串联调用吗? insert
是否需要find
任何东西? 例如,如果您在插入之前需要检查一条logging,那么正确的解决scheme看起来就像这样
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'); } }); } });
注意这里的区别? 请记住, find
和insert
是非阻塞调用,因此在您的示例中,您不能保证两个callback的运行顺序。 但是,通过将insert
调用移动到find
callback函数中,我们保证在find
之后总会调用insert
。