在node.js express中返回响应的正确方法是什么?

问题描述 投票:0回答:2

我在理解我的代码出什么问题时遇到了麻烦。我正在创建简单的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

据我了解,这与尝试多次发送响应有关。检查姓名或电子邮件后,注册功能不会结束。那里有更多代码,但原理是相同的。

我不知道,也无法在网络上找到任何信息,处理回复的正确方法是什么。

javascript node.js express
2个回答
0
投票

为了避免回调地狱,您可以使用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(...))
}

0
投票

您两次返回响应,这会导致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
                }
            );
        }
    );
}

© www.soinside.com 2019 - 2024. All rights reserved.