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

NodeJS Lambda如何在MySQL查询回调中正确返回API Gateway响应?

问题描述

我有一个通过API Gateway HTTP调用触发的Node.js Lambda函数,使用mysql库查询数据并将其作为结果返回。但无法将查询结果作为调用响应返回,总是返回对象的初始空值。示例代码如下:

import { createRequire } from 'module';
const require = createRequire(import.meta.url);

const mysql = require('mysql');

const con = mysql.createConnection({
  host: process.env.RDS_HOSTNAME,
  user: process.env.RDS_USERNAME,
  password: process.env.RDS_PASSWORD,
  port: process.env.RDS_PORT,
  database: process.env.RDS_DATABASE,
});

const tableName = 'fit_guide';

export const handler = async (event, context, callback) => {
  let response = {};
  const routeKey = event.routeKey;

  let sql = `SELECT * FROM ${tableName}`;
  con.query(sql, function (error, results, fields) {
    if (error) throw error;
    // 此处可以打印数据库表的查询结果
    console.log('******** ', results);
    // 此处无法返回结果
    response = {
      statusCode: 200,
      success: true,
      results,
    };
    callback(null, JSON.stringify(response));
    return response;
  });
  con.end();

  // 此处返回的是初始值空对象 {}
  callback(null, JSON.stringify(response));
  return response;
};
问题原因
  1. 异步回调时机问题:con.query是异步回调模式,Lambda的handler函数在执行到callback(null, JSON.stringify(response))时,数据库查询还未完成,因此返回的是初始空对象{}。
  2. 重复调用callback:代码中调用了两次callback,这会导致Lambda提前返回初始值,后续查询完成后的callback调用无效。
  3. 连接提前关闭:con.end()放在查询回调外部,会导致数据库连接在查询完成前就被关闭,可能导致查询失败或结果丢失。
解决方案

方案1:将mysql回调包装为Promise(基于原mysql库)

通过Promise包装异步查询操作,利用async/await等待查询完成后再返回结果,同时调整连接生命周期:

import { createRequire } from 'module';
const require = createRequire(import.meta.url);

const mysql = require('mysql');

const tableName = 'fit_guide';

export const handler = async (event) => {
  // 每次请求创建新连接,避免容器复用导致的连接失效
  const con = mysql.createConnection({
    host: process.env.RDS_HOSTNAME,
    user: process.env.RDS_USERNAME,
    password: process.env.RDS_PASSWORD,
    port: process.env.RDS_PORT,
    database: process.env.RDS_DATABASE,
  });

  try {
    // 将query包装为Promise,等待查询完成
    const results = await new Promise((resolve, reject) => {
      const sql = `SELECT * FROM ${tableName}`;
      con.query(sql, (error, queryResults) => {
        if (error) reject(error);
        else resolve(queryResults);
      });
    });

    // 返回查询结果,API Gateway需要正确的Content-Type头
    return {
      statusCode: 200,
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        success: true,
        results
      })
    };
  } catch (error) {
    // 捕获并返回错误信息
    console.error('数据库查询失败:', error);
    return {
      statusCode: 500,
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        success: false,
        error: error.message
      })
    };
  } finally {
    // 无论成功失败,确保关闭连接
    con.end();
  }
};

方案2:改用mysql2/promise(原生支持Promise)

使用mysql2/promise库,它原生支持Promise和async/await,代码更简洁:

import { createRequire } from 'module';
const require = createRequire(import.meta.url);

// 使用mysql2的Promise版本
const mysql = require('mysql2/promise');

const tableName = 'fit_guide';

export const handler = async (event) => {
  let connection;
  try {
    // 创建连接并等待完成
    connection = await mysql.createConnection({
      host: process.env.RDS_HOSTNAME,
      user: process.env.RDS_USERNAME,
      password: process.env.RDS_PASSWORD,
      port: process.env.RDS_PORT,
      database: process.env.RDS_DATABASE,
    });

    // 直接await查询,解构获取结果
    const [results] = await connection.execute(`SELECT * FROM ${tableName}`);

    return {
      statusCode: 200,
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        success: true,
        results
      })
    };
  } catch (error) {
    console.error('数据库查询失败:', error);
    return {
      statusCode: 500,
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        success: false,
        error: error.message
      })
    };
  } finally {
    // 确保连接关闭
    if (connection) await connection.end();
  }
};

关键改动说明

  • 异步处理:通过Promise或原生Promise库,让Lambda等待数据库查询完成后再返回结果。
  • 连接生命周期:每次请求创建新连接,避免Lambda容器复用导致的连接失效问题;用finally确保连接无论成功失败都会关闭。
  • 响应格式:添加Content-Type: application/json响应头,确保API Gateway能正确解析返回内容;直接返回响应对象,不再使用callback(async handler会自动处理返回值)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 10:55:15