Javascript 使用express.js,我得到了以下错误:未捕获错误[ERR\u HTTP\u HEADERS\u SENT]:发送到客户端后无法设置头
我想在这个问题上得到帮助。 本准则的目标是:Javascript 使用express.js,我得到了以下错误:未捕获错误[ERR\u HTTP\u HEADERS\u SENT]:发送到客户端后无法设置头,javascript,node.js,sqlite,express,routes,Javascript,Node.js,Sqlite,Express,Routes,我想在这个问题上得到帮助。 本准则的目标是: 使用请求正文的artist属性中的信息,使用指定的艺术家ID更新artist,并将其保存到数据库中。在响应正文的artist属性上返回更新艺术家的200响应 如果缺少任何必填字段,则返回400响应 如果具有提供的艺术家ID的艺术家不存在,则返回404响应 以下是失败的路线: artistsRouter.put('/:artistId', (req, res, next) => { if(areParamsRight(req.body.a
- 使用请求正文的
属性中的信息,使用指定的艺术家ID更新artist
,并将其保存到数据库中。在响应正文的artist
属性上返回更新艺术家的200响应artist
- 如果缺少任何必填字段,则返回400响应
- 如果具有提供的
艺术家ID的艺术家不存在,则返回404响应
artistsRouter.put('/:artistId', (req, res, next) => {
if(areParamsRight(req.body.artist)){ // areParamsRight checks for the correct types and body's fields
db.serialize(() => {
db.run('UPDATE Artist SET name = $name, date_of_birth = $date_of_birth, biography = $biography WHERE id = $iD',
{ $name: req.body.artist.name,
$date_of_birth: req.body.artist.dateOfBirth,
$biography: req.body.artist.biography,
$is_currently_employed: req.body.artist.isCurrentlyEmployed,
$iD: req.artist.id }, (error) => { if(error) { next(error) }
});
db.get(`SELECT * FROM Artist WHERE id = $thisId `, { $thisId: req.artist.id } , (err, artist) => {
if(err){
next(err);
} else {
res.status(200).send(artist);
console.log('response sent. ')
}
})
})
} else {
res.setStatus(400);
}
});
我尝试了以下方法:
- 使用.serialize()避免竞争条件
- 验证SQL是否有效
- 已验证请求中的数据类型
- 已检查是否已附加req.Artister.id
- 划分路线:
// this function will accept req object and will return true if params are the proper type.
function areParamsRight(obj) {
const name = obj.name, dateOfBirth = obj.dateOfBirth, biography = obj.biography;
if( Object.keys(obj).includes('name' && 'dateOfBirth' && 'biography')
&& typeof name === 'string' && typeof dateOfBirth === 'string' && typeof biography === 'string' ){
return true;
} else return false;
}
module.exports = areParamsRight;
提前感谢。当数据库调用出错时,这段代码可能会导致发送两个响应:
db.run('UPDATE Artist SET name = $name, date_of_birth = $date_of_birth, biography = $biography WHERE id = $iD',
{ $name: req.body.artist.name,
$date_of_birth: req.body.artist.dateOfBirth,
$biography: req.body.artist.biography,
$is_currently_employed: req.body.artist.isCurrentlyEmployed,
$iD: req.artist.id }, (error) => { if(error) { next(error) }
});
next();
如果将其格式化为使代码流更清晰的方式,如下所示:
artistsRouter.put('/:artistId', (req, res, next) => {
if (areParamsRight(req.body.artist)) {
db.serialize(() => {
db.run('UPDATE Artist SET name = $name, date_of_birth = $date_of_birth, biography = $biography WHERE id = $iD', {
$name: req.body.artist.name,
$date_of_birth: req.body.artist.dateOfBirth,
$biography: req.body.artist.biography,
$is_currently_employed: req.body.artist.isCurrentlyEmployed,
$iD: req.artist.id
}, (error) => {
if (error) {
next(error)
}
});
next();
})
} else {
res.setStatus(400);
}
});
您可以看到,只要areParamsRight()
返回true,那么代码将始终执行db.run()
,然后调用next()
。但是,如果db.run()
中有错误,那么代码也将调用next(error)
。但是,由于这将被异步调用,对next()
的调用已经执行,这将尝试向同一请求发送第二个响应,因此可能会生成您看到的错误类型(尝试向同一请求发送两个响应)
这有点让人困惑,这里想要的行为是什么。首先,您只想发送一个响应,而不是两个。但是,由于这是一个.put()
请求处理程序,而不是中间件处理程序,因此您似乎应该在此处发送响应,而不是调用next()
。我想应该是这样的:
artistsRouter.put('/:artistId', (req, res, next) => {
if (areParamsRight(req.body.artist)) {
db.serialize(() => {
db.run('UPDATE Artist SET name = $name, date_of_birth = $date_of_birth, biography = $biography WHERE id = $iD', {
$name: req.body.artist.name,
$date_of_birth: req.body.artist.dateOfBirth,
$biography: req.body.artist.biography,
$is_currently_employed: req.body.artist.isCurrentlyEmployed,
$iD: req.artist.id
}, (error) => {
if (error) {
next(error); // report error
} else {
res.sendStatus(200); // report success
}
});
})
} else {
res.sendStatus(400);
}
});
另外请注意,您在末尾有res.setStatus(400)
,我想您的意思是res.sendStatus(400)
注意:由于您在此路由处理程序中只运行一个数据库查询,因此似乎不需要在
db.serialize()
中包装内容。但是,我不是SQL方面的专家。areParamsRight()做什么?“请显示该代码。我已经编辑了这篇文章。你要求的是结尾。你检查的代码是试图解决这个问题。上面你看到的是主选项(第一块代码),其中没有next()
调用,但有错误的情况除外。是的,它应该只有一个响应,但代码必须执行两个查询,一个用于更新表,第二个用于获取更新的记录。我使用serialize()检查了同步性是否有问题
。如果我没有正确理解你的答案,我很抱歉。我很感激。顺便说一句,我已经修复了sendStatus()
part。我在开始时更新了帖子,以指定目标。对不起,我应该在之前这样做。@jSamsa-如果你不显示真实代码而不遗漏任何内容,我将无法进一步帮助你。你的问题只显示了一个数据库操作。问题可能是两个操作之间的协调,但你没有共享那个密码。
artistsRouter.put('/:artistId', (req, res, next) => {
if (areParamsRight(req.body.artist)) {
db.serialize(() => {
db.run('UPDATE Artist SET name = $name, date_of_birth = $date_of_birth, biography = $biography WHERE id = $iD', {
$name: req.body.artist.name,
$date_of_birth: req.body.artist.dateOfBirth,
$biography: req.body.artist.biography,
$is_currently_employed: req.body.artist.isCurrentlyEmployed,
$iD: req.artist.id
}, (error) => {
if (error) {
next(error); // report error
} else {
res.sendStatus(200); // report success
}
});
})
} else {
res.sendStatus(400);
}
});