【问题标题】:`Cannot set headers after they are sent to client` error when using mysql2 async/await使用 mysql2 async/await 时出现“发送到客户端后无法设置标头”错误
【发布时间】:2021-01-25 11:06:03
【问题描述】:

我正在更改我的后端(从 Mongo 切换到 MySql)。我知道错误正在抛出,因为在我的 SQL 查询完成之前正在执行 return 语句,然后当我的 sql 查询完成时,它厌倦了发送另一个 res.send,因此我尝试将 mysql2 与 Promise 包装器一起使用在我的 async 函数中的查询上使用 await

我有一个单独的文件来创建数据库连接,因此我可以在整个 Nodejs 后端访问该连接:

const mysql = require('mysql2');

async function pool(){
    const pool = await mysql.createPool({
        host: "ip",
        user: "username",
        password: "password",
        database: "db"
    });
    return pool
}

exports.getConnection = async function(callback) {
    const currentPool = await pool();
    currentPool.getConnection(function(err, conn) {
        if(err) return callback(err);
        callback(err,conn)
    });
};

然后,创建一个遵循 async/await 的查询:

sql.getConnection(async function(err, client){
        client.query(`select email from users where email = "${email}"`, function (error, result){
            if(error) return res.status(500).send('an internal db error occurred');
            // carry on with code ...
    });
});

我也尝试在查询中使用await

await sql.getConnection(async function(err, client){
        client.query(`select email from users where email = "${email}"`, function (error, result){
            if(error) return res.status(500).send('an internal db error occurred');
            // carry on with code ...
    });
});

我错过了什么?我还没有厌倦使用普通的mysql NPM 库并制作自己的 promise 包装器......

新代码:

我已经更新了我的功能:

const mysql = require('mysql2');

const pool = mysql.createPool({
    host: "ip",
    user: "user",
    password: "pass",
    database: "db"
});

exports.db = (sql) => {
    new Promise((resolve, reject) => {
        pool.getConnection((err, conn) => {
            if(err) return reject(err);

            conn.query(sql, (err, results, fields) => {
                conn.release()
                if(err) return reject(err)
                console.log(results)
                resolve(results);
            });
        });
    });
}

然后我通过以下方式调用它:

try{
    const emailExisit = await sql.db(`SELECT email FROM users WHERE email = "${email}"`);
    console.log(emailExisit);
    if(emailExisit.length > 0) return res.status(422).send({"data": "", "code": "105", "message": "An account with given email already exists"});
}catch (err) {
    console.log(err)
    return res.status(500).send({"data": "", "code": "108",  "message": `There seems to be an error contacting the database. Try again later <br> ${err}`});
}

但是,我的代码仍在继续,留下我的 emailExists 变量 undefined(是的,它在 async function 内)

【问题讨论】:

  • 请也显示端点本身
  • 您的getConnection() 函数需要重新设计。以你正在做的方式混合回调和异步/等待是一团糟。选择一种或另一种,并在任何地方都坚持使用它。由于您使用的是 mysql2,因此您应该只使用 Promise 并从代码中的任何位置消除普通的异步回调。
  • @jfriend00 好吧,我在其他脚本中到处都使用异步回调,那么使用async/await 的最佳方法是什么?
  • 使用require('mysql2/promise')代替require('mysql2')
  • 您必须向我们展示实际的请求处理程序代码(从头到尾,包括发送任何响应的位置),以便我们知道您在哪里犯了导致此错误消息的错误。

标签: javascript mysql node.js async-await mysql2


【解决方案1】:

这是我将 MySQL 与 Node.js 一起使用的配置。我希望它对你有用。

/config/mysql.js

const mysql = require('mysql2');

const pool = mysql.createPool({
  host: process.env.MYSQL_HOST,
  user: process.env.MYSQL_USER,
  password: process.env.MYSQL_PASSWORD,
  port: process.env.MYSQL_PORT,
  database: process.env.MYSQL_DB_NAME,
});

const query = (query, args = []) =>
  new Promise((resolve, reject) => {
    pool.getConnection((err, connection) => {
      if (err) {
        return reject(err);
      }
      connection.query(query, args, (err, results) => {
        connection.release();
        if (err) {
          return reject(err);
        }
        resolve(results);
      });
    });
  });

module.exports = { query };


/index.js

const { query } = require('./mysql');
const express = require('express');
const bodyParser = require('body-parser');

const app = express();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded());

app.get('/api/v1/sum', (req, res) => {
  query('SELECT 1 + 1 as sum')
    .then(results => {
      res.json({ sum: results[0].sum });
    })
    .catch(err => {
      console.error(err);
      res.status(500).json({ error: 'error msg' });
    });
});

// anther example with async
app.get('/api/v1/sum', async (req, res) => {
  try {
    const results = await query('SELECT 1 + 1 as sum');
    res.json({ sum: results[0].sum });
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: 'error msg' });
  }
});

app.listen(3000);

【讨论】:

  • 有趣的是,在你发送这个之前我刚刚重写了我自己的函数,它看起来和你的一样。但是,似乎await 仍然无法在我的身上运行,因为try/catchawait 语句下方的代码仍在运行,我已经更新了我的问题,你能看看吗?
  • @Nathan 你需要在exports.db 中返回new Promise,因为exports.db 现在将返回未定义。
  • 只需将new Promise((resolve, reject) =&gt; { 替换为return new Promise((resolve, reject) =&gt; {
  • ARHHHH 另一个简单的错误....上帝我讨厌编码。谢谢!
猜你喜欢
  • 2020-08-04
  • 2019-10-20
  • 1970-01-01
  • 1970-01-01
  • 2021-11-02
  • 2020-07-11
相关资源
最近更新 更多