简体   繁体   English

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

[英]What is the proper way of returning responses in node.js express?

I am having trouble understanding what is wrong with my code.我无法理解我的代码有什么问题。 I am creating simple node.js REST api and I'm getting error no matter what I do:我正在创建简单的 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'

The code that is causing the error is as follows:导致错误的代码如下:

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',
        });
      }
    }
  );

where line 38 is:其中第 38 行是:

return res.status(400).json({ message: 'Name taken' });

However the response is correct and I'm getting error 400 with error set to Mail taken但是响应是正确的,并且我收到错误 400, error设置为已发送Mail taken

From my understanding this has something to do with trying to send the response multiple times.据我了解,这与尝试多次发送响应有关。 Register function doesn't end after checking whether the name or email are taken.寄存器 function 在检查名称或 email 是否被占用后没有结束。 There is more code there, but the principle will be the same.那里有更多的代码,但原理是一样的。

I don't know nor can find any information on the web what is the correct way to handle responses.我不知道也找不到关于 web 的任何信息,什么是处理响应的正确方法。

You are returning the response twice, which causes the cannot set headers error.您要返回两次响应,这会导致cannot set headers错误。 You would need to run the second mysql.query within the callback function of the first.您需要在第一个的回调 function 中运行第二个mysql.query Alternatively, you can run each of this queries using async await .或者,您可以使用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
                }
            );
        }
    );
}

To avoid callback hell you could use promises and manage your state outside the asynchronous parts.为了避免回调地狱,您可以使用承诺并在异步部分之外管理您的 state。 Maybe, whatever your mysql is, it already provides a promise based interface.也许,无论您的mysql是什么,它已经提供了一个基于 promise 的接口。

I'll provide you some abstract code:我将为您提供一些抽象代码:

If you can use async/await:如果您可以使用异步/等待:

// "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(...))
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Node.js / Express框架中将数据传递到d3以呈现图形数据的正确方法是什么 - What is the proper way in Node.js/Express framework to pass data to d3 for rendering graphical data 终止Node.js服务器请求的正确方法是什么? - What's the proper way of terminating a Node.js server request? Node.js:拆分代码的正确方法是什么? - Node.js: What is the proper way of splitting code? 使用node.js postgresql模块的正确方法是什么? - What is the proper way to use the node.js postgresql module? 在Node.js 7中,什么是压缩UnhandledPromiseRejectionWarning的正确方法? - In Node.js 7 what is the proper way to suppress UnhandledPromiseRejectionWarning? 在Node.js中链接异步函数的正确方法是什么? - What's the proper way of chaining async functions in Node.js? 在Node.js中要求的正确方法是什么? - What's the proper way to require in Node.js? 启动多个本地 node.js 服务器的正确方法是什么? - What is the proper way to start multiple local node.js servers? 在express.js / node.js中包含标头+自定义服务器端.js的正确方法? - Proper way to include headers + custom server-side .js in express.js / node.js? Node.js 快递发送原始 HTTP 响应 - Node.js express send raw HTTP responses
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM