调用Node.js/Express服务端接口时,客户端未捕获错误导致React Hook状态无法更新
问题根本原因
原生fetch(不管是浏览器端还是Node.js 18+内置版本)的Promise状态判定逻辑和多数开发者的直觉存在偏差:
- 只有出现完全无法收到HTTP响应的场景(比如网络断开、DNS解析失败、CORS跨域拦截),才会将Promise置为rejected,触发
catch回调 - 只要目标服务器能返回任何HTTP响应(哪怕状态码是404、500这类错误状态),
fetch都会将Promise置为resolved,走then分支
你当前场景里,服务端在第三方链接无效时会正常返回404状态码——这个响应对客户端的fetch来说是完全合法的可解析响应,根本不会触发catch回调,所以写在catch里的setSyncTest("fail")永远不会执行,这就是状态不更新的核心原因。
修复方案
需要分别调整服务端、客户端的代码逻辑,手动补全fetch缺失的HTTP状态校验:
服务端路由优化
原服务端代码只在fetch完全无响应时返回404,没有覆盖“第三方接口返回404但能正常收到响应”的场景,优化后统一用async/await做异常捕获,主动校验第三方响应状态:
const testSync = async (req, res) => { try { const response = await fetch(bookingLink, requestOptions) // 主动判断第三方响应是否为2xx成功状态 if (!response.ok) { throw new Error(`目标链接无效,响应状态码:${response.status}`) } res.sendStatus(200) } catch (error) { console.log('sync测试错误', error) // 返回结构化的错误响应,方便客户端识别 res.status(404).json({ success: false, error: error.message }) } } router.post('/test-sync', testSync);
客户端调用逻辑修正
去掉对fetch自动识别HTTP错误的依赖,在then分支里主动校验响应状态,非成功状态主动抛错,让错误统一进入catch分支处理:
fetch(`${protocol}//${domainName}/api/test-sync`, requestOptions) .then(async response => { // 主动校验HTTP状态,非2xx直接抛错 if (!response.ok) { throw new Error(`后端接口响应异常,状态码:${response.status}`) } setSyncTest("success") }) .catch(error => { // 网络错误、主动抛出的HTTP状态错误都会统一走到这里 console.log('sync测试失败', error) setSyncTest("fail") })
常见误区说明
很多开发者会把原生fetch的错误判定逻辑和axios等三方请求库搞混:
axios默认会把所有非2xx的HTTP响应判定为请求错误,直接触发catch回调- 原生
fetch没有内置这个逻辑,DevTools控制台打印的404状态码只是浏览器对网络请求状态的可视化提示,不会触发fetch的Promise rejection,必须手动读取响应的ok属性(该属性为true当且仅当响应状态码在200-299区间)来识别错误。
内容的提问来源于stack exchange,提问作者Bogos Robert
相关产品推荐
相关产品推荐

