You need to enable JavaScript to run this app. JavaScript async/await调用接口未等前序请求完成执行后续请求问题
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript async/await调用接口未等前序请求完成执行后续请求问题

问题原因

  1. 服务端数据库操作是异步回调逻辑,当前代码没有等待数据库插入、查询ID的操作完成就提前返回了响应:你在con.query的回调函数外直接判断successful并返回响应,此时插入Rabbit表、查询最大ID的异步操作还没执行完,客户端拿到200响应时lastInsertedRId还没被赋值。
  2. 用全局变量存储lastInsertedRId存在严重的并发问题:如果同时有多个用户提交请求,不同请求的ID会互相覆盖,完全无法保证外键关联正确性。
  3. 存在冗余查询风险:插入自增ID后不需要手动查询max(R_ID),数据库插入结果里直接返回了最新插入的自增ID,直接取即可,查询最大值的逻辑在高并发场景下也可能拿到别的请求插入的ID。

解决方案

第一步:改造服务端/updateRtable接口

  • 将响应返回逻辑移到数据库操作的回调最内层,确保所有操作完成后再返回
  • 直接取插入结果的insertId获取最新ID,废弃查询max ID的逻辑
  • 把新生成的rabbitID直接返回给客户端,不再用全局变量存储
    改后的代码:
app.post("/updateRtable", (req, res) => {
  console.log("went inside rabbit");
  console.log(req.body.RName);
  con.query(`INSERT INTO RABBIT(R_ID, RABBIT_NAME, DATE_OF_BIRTH, RABBIT_STATUS, SEX, BREED) VALUES (NULL, '${req.body.RName}', '${req.body.dob}', '${req.body.rStat}', '${req.body.sex}', '${req.body.breed}')`, function(err, result) {
    if (err) {
      console.log(err);
      return res.status(ERROR_STATUS_CODE).send({
        success: false
      });
    }
    // 直接取插入结果自带的自增ID,不需要额外查询
    const lastInsertedRId = result.insertId;
    // 所有操作完成再返回,同时把ID返回给客户端
    res.status(200).send({
      success: true,
      rabbitId: lastInsertedRId
    });
  });
});

第二步:改造服务端/updateMyStable接口

不再读取全局的lastInsertedRId,改为从请求参数中取客户端传递的rabbitId:

app.post("/updateMyStable", (req, res) => {
  console.log("went inside mystuff table");
  // 从请求参数中取rabbitId,不要用全局变量
  const rabbitId = req.body.rabbitId;
  con.query(`INSERT INTO MYSTUFF(R_ID, NOTES, Kibble, Carrier, Medication, Treats, Blankets, Toys, Drop_off_Date, Pick_up_Date) VALUES ('${rabbitId}', '${req.body.notes}', '${req.body.kibble}', '${req.body.carrier}', '${req.body.medic}', '${req.body.treats}', '${req.body.blankets}', '${req.body.toys}', '${req.body.dropD}', '${req.body.picKD}')`, function(err, result) {
    if (err) {
      console.log(err);
      return res.status(ERROR_STATUS_CODE).send("Server side error");
    }
    res.status(200).send({
      success: true
    });
  });
});

第三步:改造客户端逻辑

第一个请求拿到返回的rabbitId后,添加到第二个请求的表单参数中再发送:

async function updateAllHelper(formDataParam) {
  // 等待第一个接口完成,拿到返回的rabbitId
  let updateRResult = await updateRabbitTable(formDataParam);
  if (!updateRResult.success) {
    console.log("更新Rabbit表失败");
    return;
  }
  // 把rabbitId添加到表单参数中
  formDataParam.append('rabbitId', updateRResult.rabbitId);
  // 再发起第二个请求
  let updateMySResult = await updateMyStable(formDataParam);
}

// 下面两个请求函数原有逻辑不需要改动
async function updateRabbitTable(formDataParam) {
  let headers = new Headers();
  const response = await fetch("/updateRtable", {
    method: "POST",
    body: formDataParam,
    headers
  });
  const body = await response.json();
  return body;
}

async function updateMyStable(formDataParam) {
  let headers = new Headers();
  const response = await fetch("/updateMyStable", {
    method: "POST",
    body: formDataParam,
    headers
  });
  const body = await response.json();
  return body;
}

额外优化建议

你当前的SQL写法存在SQL注入风险,建议改用参数化查询替换字符串拼接的写法,避免恶意参数破坏数据库。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.16 18:15:09