You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Callback Function返回undefined问题:Node.js数据库查询代码求助

排查Callback返回undefined的异步操作问题

兄弟,你的问题核心是没搞懂异步操作的返回逻辑——你在conn.query的回调里return token,但这个return根本不会让queryDB函数返回值,更别说上层的searchAccessToken了。咱们一步步拆解问题,再给你修正方案:

问题出在哪?

1. queryDB函数的异步陷阱

conn.query是异步执行的,你在它的回调函数里写的return token,只是结束了这个回调函数本身,不会让queryDB返回任何值。而且queryDB函数本身没有任何顶层的return语句,所以它默认返回undefined。

这就导致searchAccessToken里的return callback(sql),实际上是return了queryDB(sql)的结果——也就是undefined,所以你的console.log自然输出undefined。

2. 同步调用异步函数的错误

你直接用console.log(searchAccessToken(name,queryDB))试图同步获取异步操作的结果,这本身就不符合异步代码的逻辑。异步操作的结果只能通过回调、Promise或者async/await来获取,不能直接同步return。

修正方案(回调版本)

咱们先把代码改成标准的回调风格,贴合你原来的写法:

第一步:修复queryDB,让它支持回调传递结果

function queryDB(sql, callback){
  db(function(err, conn){
    // 先处理数据库连接错误
    if (err) {
      return callback(err);
    }
    conn.query(sql, function(err, results){
      // 不管成功失败,一定要释放连接
      conn.release();
      
      if(err){
        return callback(err); // 传递查询错误
      }
      
      // 有结果就返回token,没结果返回空字符串
      const token = results.length ? results[0].accessToken : "";
      callback(null, token);
    });
  });
}

第二步:调整searchAccessToken的逻辑

不需要return callback的结果,直接把回调传递给queryDB即可:

function searchAccessToken(emailAddress, callback){
  // 注意:这里有SQL注入风险!后面会说怎么改
  var sql = "SELECT accessToken FROM device WHERE email_address = '" + emailAddress + "'";
  queryDB(sql, callback);
}

第三步:正确调用并获取结果

不能直接console.log,要通过回调拿到异步结果:

searchAccessToken(name, function(err, token) {
  if (err) {
    console.error('查询失败:', err);
    return;
  }
  console.log('获取到的AccessToken:', token);
});

额外提醒:SQL注入风险!

你现在直接把emailAddress拼接到SQL语句里,这是非常危险的,攻击者可以通过构造恶意邮箱地址来执行任意SQL语句。赶紧改成参数化查询:

修正searchAccessToken和queryDB支持参数化:

// searchAccessToken里用占位符?代替直接拼接
function searchAccessToken(emailAddress, callback){
  var sql = "SELECT accessToken FROM device WHERE email_address = ?";
  queryDB(sql, [emailAddress], callback); // 把参数作为数组传递
}

// 调整queryDB支持参数
function queryDB(sql, params, callback){
  // 兼容如果params是回调的情况(可选)
  if (typeof params === 'function') {
    callback = params;
    params = [];
  }
  
  db(function(err, conn){
    if (err) {
      return callback(err);
    }
    // 把参数数组传给conn.query
    conn.query(sql, params, function(err, results){
      conn.release();
      if(err){
        return callback(err);
      }
      const token = results.length ? results[0].accessToken : "";
      callback(null, token);
    });
  });
}

进阶:用Promise/async-await简化代码

如果你的Node.js版本支持,用Promise或者async/await会让异步代码更易读:

// 先把db包装成Promise
const getConnection = () => {
  return new Promise((resolve, reject) => {
    pool.getConnection((err, conn) => {
      if (err) reject(err);
      else resolve(conn);
    });
  });
};

// queryDB改成Promise版本
function queryDB(sql, params){
  return getConnection().then(conn => {
    return new Promise((resolve, reject) => {
      conn.query(sql, params, (err, results) => {
        conn.release();
        if (err) reject(err);
        else {
          const token = results.length ? results[0].accessToken : "";
          resolve(token);
        }
      });
    });
  });
}

// searchAccessToken也改成Promise
function searchAccessToken(emailAddress){
  const sql = "SELECT accessToken FROM device WHERE email_address = ?";
  return queryDB(sql, [emailAddress]);
}

// 用async/await调用
async function getToken() {
  try {
    const token = await searchAccessToken(name);
    console.log('获取到的AccessToken:', token);
  } catch (err) {
    console.error('查询失败:', err);
  }
}

getToken();

这样代码逻辑更清晰,也避免了回调嵌套的问题。

内容的提问来源于stack exchange,提问作者jdotdoe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:14:26