js fetch网络请求实战
fetch 实战不只发请求:避开常见坑,写出稳健的网络层代码
如今做前端项目,提到网络请求,不少人第一反应还是直接套 axios。但原生 fetch 作为浏览器内置 API,不增加打包体积,底层行为透明。掌握它的脾气,不仅能独立搭建轻量通信层,遇到跨域拦截或接口联调卡顿时也能迅速定位。很多人用 fetch 踩过的坑,往往不是语法记不住,而是没摸清它的异常边界。咱们直接切入真实开发场景,把那些文档里一笔带过却致命的细节拆开看。
拿到响应后处理数据,是第一步也是最容易翻车的地方。拿到响应后别急着调 .json(),先检查 Content-Type 响应头。服务端偶尔会因为网关转发或权限校验失败,吐出一段 HTML 报错页面或纯文本。此时强制解析只会触发 SyntaxError 导致整个请求链中断。更稳妥的做法是先用 .text() 读取原始内容,通过正则或字符串匹配确认数据结构,再进入 try...catch 进行 JSON 转换。这种防御性编程习惯,能让你的页面在接口抖动时依然保持可降级状态。
fetch 最反直觉的设计在于 Promise 的决议规则。主动捕获 HTTP 状态码,将 4xx/5xx 转化为 reject 错误。它不会因为服务器返回 404 或 500 而拒绝 Promise,只会走 resolve 通道,响应的 ok 属性为 false。如果直接把数据往下传,前端渲染层只会收到一串空壳或错误日志。正确思路是在每次请求末尾判断 !response.ok,一旦发现非法状态码,立即 throw new Error([response.status] + ${requestUrl})。让错误带上状态码与请求路径,下游的 Toast 提示或路由守卫才能精准拦截,避免用户对着空白页发呆。
实际对接业务时,身份验证与跨域凭据是绕不开的硬仗。显式声明 credentials: 'include' 携带凭证。fetch 默认遵循“同源策略洁癖”,不附带 Cookie 也不发送 Authorization 头。如果你做的是后台管理系统或需要维持登录态的 SPA,忽略这行配置会导致令牌丢失,页面瞬间退回登录页。针对内部微服务架构,建议在封装层统一注入 headers: { 'X-Token': store.token },并在初始化时按需开启 mode: 'cors'。配置写对,能省去大量调试抓包的时间。
用户交互节奏快,请求堆叠引发的竞态条件常让老手也头疼。上一页数据还没渲染完,用户已经切到下一页,或者连续快速提交表单。使用 AbortController 管理信号,及时终止过期请求。给每个出站请求绑定独立的 Controller 实例,在 init 参数中传入 signal。当组件卸载、用户点击取消或发起同类型新请求时,调用 controller.abort() 切断连接。这不仅是释放内存的最佳实践,更能彻底杜绝“后发请求先返回”导致的数据覆盖事故。
fetch 本身只是块轻量的砖,砌成什么结构全看你怎么填缝。把它当成可控的基础设施而非黑盒,理清响应解析、状态转换、凭证传递与生命周期管理这几道关卡,写出的网络层代码自然扎实耐打。下次面对复杂的请求链路时,不妨多留意原生 API 的能力清单,少一层过度包装,多一层细节把控,开发节奏会更从容。


还没有评论,来说两句吧...