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

我想在这个问题上得到帮助。 本准则的目标是:

  • 使用请求正文的
    artist
    属性中的信息,使用指定的艺术家ID更新
    artist
    ,并将其保存到数据库中。在响应正文的
    artist
    属性上返回更新艺术家的200响应
  • 如果缺少任何必填字段,则返回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
  • 划分路线:
下面是helper函数。它似乎工作正常,因为它也用于邮政路线

// 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);
    }
});