我在理解我的代码出什么问题时遇到了麻烦。我正在创建简单的node.js REST api,无论我做什么我都会出错:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:535:11)
at ServerResponse.header (D:\04. MOJE\08. STUDIA\6 semestr\Wybrane technologie webowe\Projekt\silicon store api\node_modules\express\lib\response.js:771:10)
at ServerResponse.send (D:\04. MOJE\08. STUDIA\6 semestr\Wybrane technologie webowe\Projekt\silicon store api\node_modules\express\lib\response.js:170:12)
at ServerResponse.json (D:\04. MOJE\08. STUDIA\6 semestr\Wybrane technologie webowe\Projekt\silicon store api\node_modules\express\lib\response.js:267:15)
at Query.<anonymous> (D:\04. MOJE\08. STUDIA\6 semestr\Wybrane technologie webowe\Projekt\silicon store api\controllers\users.js:38:32)
at Query.<anonymous> (D:\04. MOJE\08. STUDIA\6 semestr\Wybrane technologie webowe\Projekt\silicon store api\node_modules\mysql\lib\Connection.js:526:10)
at Query._callback (D:\04. MOJE\08. STUDIA\6 semestr\Wybrane technologie webowe\Projekt\silicon store api\node_modules\mysql\lib\Connection.js:488:16)
at Query.Sequence.end (D:\04. MOJE\08. STUDIA\6 semestr\Wybrane technologie webowe\Projekt\silicon store api\node_modules\mysql\lib\protocol\sequences\Sequence.js:83:24)
at Query._handleFinalResultPacket (D:\04. MOJE\08. STUDIA\6 semestr\Wybrane technologie webowe\Projekt\silicon store api\node_modules\mysql\lib\protocol\sequences\Query.js:149:8)
at Query.EofPacket (D:\04. MOJE\08. STUDIA\6 semestr\Wybrane technologie webowe\Projekt\silicon store api\node_modules\mysql\lib\protocol\sequences\Query.js:133:8) {
code: 'ERR_HTTP_HEADERS_SENT'
导致错误的代码如下:
exports.register = function (req, res) {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() });
}
var userId;
// check whether email is taken
mysql.query(
'SELECT email FROM users where email = ?',
[req.body.email],
(err, rows, fields) => {
if (err) {
return res.sendStatus(500);
}
if (rows.length > 0) {
return res.status(400).json({
message: 'Mail taken',
});
}
}
);
// check whether name is taken
mysql.query(
'SELECT name FROM users where name = ?',
[req.body.name],
(err, rows, fields) => {
if (err) {
return res.status(500);
}
if (rows.length > 0) {
return res.status(400).json({
message: 'Name taken',
});
}
}
);
第38行是:
return res.status(400).json({ message: 'Name taken' });
但是响应正确,并且在将error
设置为Mail taken
时出现错误400
据我了解,这与尝试多次发送响应有关。检查姓名或电子邮件后,注册功能不会结束。那里有更多代码,但原理是相同的。
我不知道,也无法在网络上找到任何信息,处理回复的正确方法是什么。
为了避免回调地狱,您可以使用promise并在异步部分之外管理状态。也许,无论您的mysql
是什么,它都已经提供了基于Promise的界面。
我将为您提供一些抽象代码:
如果可以使用异步/等待:
// "promisified" email check
function checkEmail(email) {
return new Promise((resolve, reject) => {
mysql.query(
'SELECT email FROM users where email = ?',
email,
(err, rows, fields) => {
if (err) {
reject({status: 500});
}
if (rows.length > 0) {
reject({
status: 400,
message: 'Mail taken'
})
}
resolve()
})
})
}
// ... same for name or genralized function
exports.register = async function(req, res) {
// ...
const emailOk = checkEmail(req.body.email)
const nameOk = checkName(req.body.name)
// ...
await Promise.all([
emailOk,
nameOk
])
.then(() => console.log('both ok'))
.catch(e => res.status(e.status).json(...))
}
您两次返回响应,这会导致cannot set headers
错误。您将需要在第一个的回调函数中运行第二个mysql.query
。或者,您可以使用async
await
运行每个查询。
exports.register = function (req, res) {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() });
}
var userId;
// check whether email is taken
mysql.query(
'SELECT email FROM users where email = ?',
[req.body.email],
(err, rows, fields) => {
if (err) {
return res.sendStatus(500);
}
if (rows.length > 0) {
return res.status(400).json({
message: 'Mail taken',
});
}
// check whether name is taken
mysql.query(
'SELECT name FROM users where name = ?',
[req.body.name],
(nameErr, nameRows, fields) => {
if (nameErr) {
return res.status(500);
}
if (nameRows.length > 0) {
return res.status(400).json({
message: 'Name taken',
});
}
// if no errors, run the rest of your code here
}
);
}
);
}