我想帮助解决以下问题。我正在撰写我的博士论文,而这一小部分代码将负责注册用户。 (我实际上是nodejs的新手)。我也在使用快递和猫鼬。
我想处理请求数据,并检查一些错误,首先我想检查是否所有字段都存在,其次,如果有人已经注册了这个电子邮件地址。
根据错误(或成功),我想发送不同的回复。如果一个字段丢失,那么400 Bad请求(如果用户存在)则409 Conflict,200 OK,如果一切正常。但是我只想做回调如果没有错误,但我有点卡在这里...我得到错误无法在发送后设置标题,这实际上很明显,因为JS继续处理代码即使设置了响应。
app.post('/register', function (req, res) {
var user = new User(req.body);
checkErrors(req, res, user, registerUser);
});
var registerUser = function(req, res, user){
user.save(function(err, user){
if (err) return console.log(err);
});
res.sendStatus(200);
};
var checkErrors = function(req, res, user, callback){
var properties = [ 'firstName', 'lastName', 'email', 'password', 'dateOfBirth' ];
for(var i = 0; i < properties.length; i++){
if(!req.body.hasOwnProperty(properties[i])){
res.status(400).send('field ' + properties[i] + ' not found');
}
}
var criteria = {
email: req.body.email
};
User.find(criteria).exec(function(err, user){
if(user.length > 0){
res.status(409).send('user already exists');
}
});
callback(req, res, user);
};
我认为问题出在for
的checkErrors
循环中。由于你在循环中调用res.status(400).send()
,你最终可以多次调用它,这将在第一次调用后触发错误,因为响应已经被发送回客户端。
在循环内部,您可以将缺少的字段添加到数组中,然后检查数组的长度以查看是否应该使用400
进行响应或继续。这样,你只会打电话给res.status(400).send()
一次。
例如:
...
var missingFields = [];
for(var i = 0; i < properties.length; i++){
if(!req.body.hasOwnProperty(properties[i])){
missingFields.push(properties[i]);
}
}
if(missingFields.length > 0) {
return res.status(400).send({"missingFields" : missingFields});
}
...
一般来说,我建议你把return
放在每个res.send()
电话前面,以确保以后没有人意外打电话。
一个例子是:
User.find(criteria).exec(function(err, user){
// We put return here in case you later add conditionals that are not
// mutually exclusive, since execution will continue past the
// res.status() call without return
if(user.length > 0){
return res.status(409).send('user already exists');
}
// Note that we also put this function call within the block of the
// User.find() callback, since it should not execute until
// User.find() completes and we can check for existing users.
return callback(req, res, user);
});
你可能注意到我移动了callback(req, res, user)
。如果我们将callback(req, res, user)
留在User.find()
回调体外,它可能会在User.find()
完成之前执行。这是使用Node.js进行异步编程的难点之一。当任务完成时,回调函数会发出信号,因此如果您没有在回调中包装想要连续的操作,则可以与源代码“无序”地执行。
另外,在函数registerUser
中,如果user.save
失败,那么客户端将永远不会知道,因为该函数为任何请求发送200
状态代码。出现这种情况的原因与上面提到的相同:因为res.sendStatus(200)
没有包含在user.save
回调函数中,所以它可能在保存操作完成之前运行。如果在保存期间发生错误,您应该告诉客户端,可能使用500
状态代码。例如:
var registerUser = function(req, res, user){
user.save(function(err, user){
if (err) {
console.error(err);
return res.status(500).send(err);
}
return res.sendStatus(201);
});
};
你对registerUser()
的调用是在路线之后定义的,因为它不是一个悬挂的函数,所以它将是undefined
。
你在封闭中使用scope
是不正确的。对于您的特定错误,这是因为您在循环中运行res.send()
时,它应该每个请求被调用一次(因此已经发送了已经发送的标题a.k.a.响应)。你也应该在调用res.send()
之后直接从函数返回。