前端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); }); }
问题原因分析
- 后端提前返回响应:在
/updateAgentTeam接口的then回调中,先执行了res.send(response.data),直接返回200状态的响应,后续postAgentToTeam的错误无法再修改响应状态。 - 后端错误未向上传递:
postAgentToTeam内部捕获错误仅打印日志,没有将错误抛出到上层接口处理,导致前端无法感知。 - 前端未处理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
相关产品推荐
相关产品推荐

