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

前端Fetch始终返回200,服务器返回400错误时如何获取正确响应?

问题:前端Fetch无法获取服务器返回的400错误状态

我编写了前端processFile函数处理上传文件,循环调用/updateAgentTeam接口。通过命令行确认服务器该接口返回400错误,但前端Fetch始终拿到200状态,无法获取正确的错误响应。

前后端代码

前端函数

function processFile() {
  var fileToLoad = document.getElementById("fileToLoad").files[0];
  var url;

  var fileReader = new FileReader();
  fileReader.onload = function(fileLoadedEvent) {
    var rows = fileLoadedEvent.target.result.split("\n");
    for (var i = 0; i < rows.length - 1; i++) {
      var cells = rows[i].split(",");
      console.log("AgentteamID=" + cells[0] + " SkilltargetID=" + cells[1] + " flag=" + cells[2]);
      url = "/updateAgentTeam?agentTeamID=" + cells[0] + "&skillTargetID=" + cells[1] + "&flag=" + cells[2],
        console.log("URL=" + url);
      const response = fetch(url, {
        method: 'GET',
        headers: {
          'Content-Type': 'application/json',
        },

      }).then(response =>
        response.json().then(data => ({
          data: "success",
          status: response.status
        })).then(res => {
          var statusCode = JSON.stringify(res.status);
          document.getElementById("Success_comment").value += JSON.stringify(res) + "---" + url;
          console.log("final result " + JSON.stringify(res) + "---" + url);

        }))

    }
  }
  fileReader.readAsText(fileToLoad, "UTF-8");
}

服务器端代码(当前仅使用Flag A分支)

app.get("/updateAgentTeam", (req, res) => {
  var skillTargetID = req.query.skillTargetID;
  console.log("req.query.skillTargetID =" + req.query.skillTargetID);
  var agentTeamID = req.query.agentTeamID;
  var flag = req.query.flag;
  var finalurl = "http://198.18.133.11/unifiedconfig/config/agentteam/" + agentTeamID;
  var xml;
  axios({
      url: finalurl,
      method: "get",
      auth: {
        username: "xxx",
        password: "yyy"
      },
    })
    .then(async(response) => {
      xml = response.data;
      res.send(response.data);

      if (flag === 'D') {
        agentremovedXML = removeAgentFromXML(xml, skillTargetID);
        postAgentToTeam(agentTeamID, agentremovedXML);
      } else if (flag === 'A') {
        AgentXML = await generateAgentXML(skillTargetID);
        console.log("Returned agent xml is " + JSON.stringify(AgentXML));
        console.log("xml where agent to be add " + JSON.stringify(xml));
        if (JSON.stringify(xml.agentCount) == 0) {
          AgentXML = {
            "agent": [AgentXML]
          };

          xml.agents = [AgentXML];
          console.log("xml with zero agents " + JSON.stringify(xml));
        } else {
          xml.agents[0].agent.push(AgentXML);
          console.log("Compare " + JSON.stringify(xml));
        }
        console.log("xml send to postAgentToTeam is " + xml);
        postAgentToTeam(agentTeamID, xml);
      }
    })
    .catch((err) => {
res.status(400);
      res.send(err.response.status);
      console.log(err);
    });
});

async function postAgentToTeam(agentTeamID, xml) {
  var teamurl = "http://198.18.133.11/unifiedconfig/config/agentteam/" + agentTeamID;
  xml.agents = xml.agents[0].agent.map(agent => ({
    agent: agent
  }));
  js2xml = json2xml(JSON.parse(JSON.stringify(xml)));
  json2 = "<agentTeam>" + js2xml + "</agentTeam>";
  response = await axios({
      url: teamurl,
      method: "put",
      auth: {
        username: "administrator@dcloud.cisco.com",
        password: "C1sco12345"
      },
      data: json2,
      headers: {
        'Content-Type': 'application/xml; charset=utf-8'
      }
    })
    .then(response => {
      console.log("hellooo " + response.status);
    })
    .catch((err) => {
      console.log(err.response.data.apiError);
      console.log("error res is " + err.response.status);
    });
}

问题原因分析

  1. 后端提前返回响应:在/updateAgentTeam接口的then回调中,先执行了res.send(response.data),直接返回200状态的响应,后续postAgentToTeam的错误无法再修改响应状态。
  2. 后端错误未向上传递:postAgentToTeam内部捕获错误仅打印日志,没有将错误抛出到上层接口处理,导致前端无法感知。
  3. 前端未处理HTTP错误状态:Fetch API仅在网络失败时触发catch,4xx/5xx状态码不会自动进入异常流程,需要手动判断response.ok或response.status。

修正方案

后端修正

1. 调整响应时机,统一处理错误

app.get("/updateAgentTeam", async (req, res) => {
  var skillTargetID = req.query.skillTargetID;
  console.log("req.query.skillTargetID =" + req.query.skillTargetID);
  var agentTeamID = req.query.agentTeamID;
  var flag = req.query.flag;
  var finalurl = "http://198.18.133.11/unifiedconfig/config/agentteam/" + agentTeamID;
  var xml;

  try {
    const response = await axios({
      url: finalurl,
      method: "get",
      auth: {
        username: "xxx",
        password: "yyy"
      },
    });
    xml = response.data;

    if (flag === 'D') {
      agentremovedXML = removeAgentFromXML(xml, skillTargetID);
      await postAgentToTeam(agentTeamID, agentremovedXML);
    } else if (flag === 'A') {
      AgentXML = await generateAgentXML(skillTargetID);
      console.log("Returned agent xml is " + JSON.stringify(AgentXML));
      console.log("xml where agent to be add " + JSON.stringify(xml));
      if (JSON.stringify(xml.agentCount) == 0) {
        AgentXML = {
          "agent": [AgentXML]
        };
        xml.agents = [AgentXML];
        console.log("xml with zero agents " + JSON.stringify(xml));
      } else {
        xml.agents[0].agent.push(AgentXML);
        console.log("Compare " + JSON.stringify(xml));
      }
      console.log("xml send to postAgentToTeam is " + xml);
      await postAgentToTeam(agentTeamID, xml);
    }
    // 业务完成后返回成功响应
    res.status(200).send({ success: true, data: xml });
  } catch (err) {
    console.log(err);
    // 统一返回错误状态
    res.status(400).send({ error: err.message, status: err.response?.status || 400 });
  }
});

2. 修改postAgentToTeam让错误冒泡

async function postAgentToTeam(agentTeamID, xml) {
  var teamurl = "http://198.18.133.11/unifiedconfig/config/agentteam/" + agentTeamID;
  xml.agents = xml.agents[0].agent.map(agent => ({
    agent: agent
  }));
  js2xml = json2xml(JSON.parse(JSON.stringify(xml)));
  json2 = "<agentTeam>" + js2xml + "</agentTeam";
  
  const response = await axios({
    url: teamurl,
    method: "put",
    auth: {
      username: "administrator@dcloud.cisco.com",
      password: "C1sco12345"
    },
    data: json2,
    headers: {
      'Content-Type': 'application/xml; charset=utf-8'
    }
  });
  console.log("hellooo " + response.status);
  return response;
}

前端修正

处理Fetch的HTTP错误状态,改用异步循环

function processFile() {
  var fileToLoad = document.getElementById("fileToLoad").files[0];
  var fileReader = new FileReader();
  
  fileReader.onload = async function(fileLoadedEvent) {
    var rows = fileLoadedEvent.target.result.split("\n");
    // 异步循环避免并发请求过多
    for (var i = 0; i < rows.length - 1; i++) {
      var cells = rows[i].split(",");
      console.log("AgentteamID=" + cells[0] + " SkilltargetID=" + cells[1] + " flag=" + cells[2]);
      const url = `/updateAgentTeam?agentTeamID=${cells[0]}&skillTargetID=${cells[1]}&flag=${cells[2]}`;
      console.log("URL=" + url);
      
      try {
        const response = await fetch(url, {
          method: 'GET',
          headers: {
            'Content-Type': 'application/json',
          },
        });
        
        // 判断HTTP状态是否正常
        if (!response.ok) {
          const errorData = await response.json();
          throw new Error(`请求失败:${errorData.error},状态码:${response.status}`);
        }
        
        const data = await response.json();
        const res = { data: "success", status: response.status };
        document.getElementById("Success_comment").value += JSON.stringify(res) + "---" + url + "\n";
        console.log("final result " + JSON.stringify(res) + "---" + url);
      } catch (err) {
        // 处理错误场景
        document.getElementById("Success_comment").value += `错误:${err.message}---${url}\n`;
        console.error("请求出错:", err.message, "URL:", url);
      }
    }
  }
  fileReader.readAsText(fileToLoad, "UTF-8");
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 15:01:12