Node.js 节点、快车、案例研究:“;错误:Can';t在发送后设置标题";
我的服务器崩溃,我在日志中发现以下错误:Node.js 节点、快车、案例研究:“;错误:Can';t在发送后设置标题";,node.js,mongodb,asynchronous,express,Node.js,Mongodb,Asynchronous,Express,我的服务器崩溃,我在日志中发现以下错误: Error: Can't set headers after they are sent. 我无法重现这个错误。我想我找到了一个解决方案,但我想确保我理解这个问题,下面的代码中概述了这个问题。基于,我相信它来自我的Express router中的多个res.send(..)呼叫: router.post('/adduser', function(req, res) { var msg = '(message okay)' var
Error: Can't set headers after they are sent.
我无法重现这个错误。我想我找到了一个解决方案,但我想确保我理解这个问题,下面的代码中概述了这个问题。基于,我相信它来自我的Express router中的多个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(..)
两次导致错误,那么为什么我不能重现此错误?我从未收到错误,但另一个用户收到了
有人能解释一下吗?对我的解决方案的反馈也会非常有用。您应该重新构造代码,因为您的代码中有两个异步调用
db.collection('userlist').find is called and will return later
db.collection('userlist').insert and will also return later
所以你给res.send打了两次电话
像这样的东西,你不会再给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})
})
})
您应该重新构造代码,因为您的代码中有两个异步调用
db.collection('userlist').find is called and will return later
db.collection('userlist').insert and will also return later
所以你给res.send打了两次电话
像这样的东西,你不会再给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})
})
})
关于问题的原因,您是正确的,但是,这里没有足够的信息来确定解决方案是否正确
例如,示例中的find
/insert
调用之间没有明显的关系-这些调用是否应该串联调用?insert
是否需要查找中的任何内容?例如,如果需要在插入之前检查记录是否存在,则正确的解决方案如下所示
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
是非阻塞调用,因此在您的示例中,您无法保证两个回调的运行顺序。但是,通过将insert
调用移动到find
回调中,我们可以保证insert
将始终在find
之后调用,您对问题原因的判断是正确的,但是,这里没有足够的信息来确定解决方案是否正确
例如,示例中的find
/insert
调用之间没有明显的关系-这些调用是否应该串联调用?insert
是否需要查找中的任何内容?例如,如果需要在插入之前检查记录是否存在,则正确的解决方案如下所示
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
是非阻塞调用,因此在您的示例中,您无法保证两个回调的运行顺序。但是,通过将insert
调用移动到find
回调中,我们可以保证insert
将始终在find
之后调用。是的,这是由于多次使用res.send()
。Express'res.send()
通过完成对web客户端的响应。一旦响应结束,在新的req
及其自身的res
到达之前,不应该/可以写入进一步的输出。注意,两个异步操作之间可能也存在竞争条件,并且无法保证顺序。如果要确保第二个db操作发生在第一个db操作之后,则需要手动排序,在第一个db操作完成之前不启动第二个db操作,或者在第一个db操作完成之前不插入第二个db操作的结果。最近,我也遇到了同样的问题。我使用了res.set(“连接”、“关闭”);在res.json()之后。。。这就是问题所在。我删除了res.set和wolla,它工作得很好。是的,这是由于多次使用res.send()
。Express'res.send()
通过完成对web客户端的响应。一旦响应结束,在新的req
及其自身的res
到达之前,不应该/可以写入进一步的输出。注意,两个异步操作之间可能也存在竞争条件,并且无法保证顺序。如果要确保第二个db操作发生在第一个db操作之后,则需要手动排序,在第一个db操作完成之前不启动第二个db操作,或者在第一个db操作完成之前不插入第二个db操作的结果。最近,我也遇到了同样的问题。我使用了res.set(“连接”、“关闭”);在res.json()之后。。。这就是问题所在。我移除了res.set和wolla,它工作得很好。