如何用async/await等待SQL响应,完成聚合后返回HTTP POST响应?
解决HTTP POST接口
/getDataByWeek数据为空问题 开发/getDataByWeek接口时,需要按周查询SQL数据并聚合到数组后返回客户端,但当前代码执行后prod、scarti等数组始终为空,无法获取正确结果。
错误代码示例
app.post("/getDataByWeek", (req, res) => { async function queryDB(){ let dataArray = []; var today = new Date(); for(let i=0;i<=req.body.prev_week;i++){ let currWeek = today; currWeek.setDate(currWeek.getDate() - i*7); dataArray.push(currWeek.toLocaleString().split(" ")[0].replace(",","")) } let scarti = []; let prod = []; let dateArray = []; let pool = await sql.connect(configSQL); let data = pool.request() for(var i=dataArray.length - 1;i>0;i--){ let startDate = normData(dataArray[i]); let endDate = normData(dataArray[i-1]); let query_string = "SELECT SUM(qty_good) as PRODOTTE, SUM(qty_reject) as SCARTO FROM [MESDB].[dbo].[vw_oee_data] where ent_name = 'Scatolatrice' and cast(hour_end_local as time) BETWEEN '06:00:00.000' AND '21:00:00.000' and cast(hour_end_local as date) BETWEEN '" + startDate +"' AND '" + endDate + "'"; await data.query(query_string, function (err, recordset) { prod.push(recordset.recordset[0].PRODOTTE) scarti.push(recordset.recordset[0].SCARTO) dateArray.push(endDate) }) } return prod,scarti,dateArray; } queryDB().then((prod,scarti,dateArray)=>console.log(prod)) });
问题根源
- async/await与回调混用:
await等待的是data.query的Promise,但同时传入的回调函数不会被await等待,导致循环结束时数组还未被赋值。 - 返回值错误:
return prod,scarti,dateArray是逗号表达式,实际仅返回最后一个值dateArray,无法同时返回三个数组。 - 日期对象引用问题:
let currWeek = today是引用赋值,循环中修改的是同一个Date实例,导致dataArray内的日期全部相同。 - SQL注入风险:直接拼接字符串生成SQL语句,存在严重的注入安全隐患。
修复后的代码
app.post("/getDataByWeek", async (req, res) => { try { async function queryDB() { let dataArray = []; const today = new Date(); // 修复日期引用问题:每次循环创建新的Date实例 for (let i = 0; i <= req.body.prev_week; i++) { const currWeek = new Date(today); currWeek.setDate(currWeek.getDate() - i * 7); dataArray.push(currWeek.toLocaleString().split(" ")[0].replace(",", "")); } const scarti = []; const prod = []; const dateArray = []; const pool = await sql.connect(configSQL); // 循环处理每周数据,确保等待每个查询完成 for (let i = dataArray.length - 1; i > 0; i--) { const startDate = normData(dataArray[i]); const endDate = normData(dataArray[i - 1]); // 使用参数化查询避免SQL注入 const queryString = ` SELECT SUM(qty_good) as PRODOTTE, SUM(qty_reject) as SCARTO FROM [MESDB].[dbo].[vw_oee_data] WHERE ent_name = 'Scatolatrice' AND CAST(hour_end_local AS time) BETWEEN '06:00:00.000' AND '21:00:00.000' AND CAST(hour_end_local AS date) BETWEEN @startDate AND @endDate `; // 去掉回调,直接用await获取查询结果 const result = await pool.request() .input('startDate', sql.Date, startDate) .input('endDate', sql.Date, endDate) .query(queryString); const record = result.recordset[0]; prod.push(record.PRODOTTE ?? 0); // 处理NULL值,默认填充0 scarti.push(record.SCARTO ?? 0); dateArray.push(endDate); } // 返回对象包含所有结果 return { prod, scarti, dateArray }; } const result = await queryDB(); console.log(result.prod); // 给客户端返回JSON结果 res.status(200).json(result); } catch (err) { // 错误处理,返回错误信息 console.error(err); res.status(500).json({ error: '查询失败', details: err.message }); } });
关键改进说明
- 日期处理修复:每次循环创建新的
Date实例,避免修改同一个对象导致日期错误。 - 正确使用async/await:移除
data.query的回调函数,直接用await等待查询结果,确保数组在循环过程中被正确填充。 - 返回值修正:用对象包装三个数组,保证所有结果能被正确返回。
- SQL注入防护:改用参数化查询,将日期作为参数传入,避免直接拼接字符串。
- 错误处理:添加
try/catch捕获数据库连接和查询过程中的错误,给客户端返回明确的错误响应。
内容的提问来源于stack exchange,提问作者Mattia DELLI PRISCOLI
相关产品推荐
相关产品推荐

