XMLHttpRequest(XHR)基于事件驱动、C++实现、状态机复杂,Fetch基于Promise、JS绑定、抽象层统一;XHR错误仅覆盖网络层,Fetch区分网络与HTTP错误;XHR流式支持弱且abort粗粒度,Fetch原生Stream+AbortController;XHR默认不带凭证,Fetch默认same-origin带cookie。

底层实现机制不同
XMLHttpRequest(XHR) 是浏览器早期实现的原生 API,基于事件驱动模型,内部封装了较重的同步/异步状态机,依赖 readyState 和 onreadystatechange 控制流程。它由浏览器 C++ 层直接实现(如 Chromium 中的 XMLHttpRequest 类),与网络栈(如 URLRequest / NetworkService)深度耦合,支持 abort、timeout、upload progress 等细粒度控制,但接口设计带有历史包袱(如必须调用 open() 和 send() 分离步骤)。
Fetch 是基于 Promise 的现代规范(WHATWG Fetch Standard),本质是对底层网络请求抽象层(如 Chromium 的 FetchAPI)的 JS 绑定。它不暴露连接状态细节,而是将请求/响应建模为不可变对象(Request、Response),底层复用与 Service Worker、Cache API 相同的资源加载管道。其 Promise 链式行为由浏览器 JS 引擎(如 V8)配合网络线程调度完成,不依赖事件循环中的手动状态轮询。
错误处理逻辑差异明显
XHR 只有网络失败(如 DNS 错误、连接中断)或超时才会触发 onerror;HTTP 状态码如 404、500 仍会进入 onload,需手动检查 status。这意味着“请求发出但服务端返回错误”不算“错误”,容易遗漏业务异常。
Fetch 则更严格:只要请求未被发送(如 URL 解析失败、CORS 拒绝、网络离线),才 reject Promise;而 HTTP 错误状态(4xx/5xx)**不会 reject**,仍返回 resolve 的 Response 对象,需显式调用 response.ok 或 response.status 判断。这种设计统一了“网络层失败”和“应用层失败”的边界,但也要求开发者主动处理语义错误。
对流式响应与中断控制的支持方式不同
- XHR 支持
responseType = 'stream'(部分浏览器),可通过response属性逐步读取ReadableStream,但需配合onprogress和手动解析 chunk,兼容性有限。 - Fetch 原生返回
Response.body—— 一个标准ReadableStream,可直接用getReader()或response.body.pipeTo()流式消费,与 Web Streams API 无缝集成,适合大文件下载、SSE、实时日志等场景。 - 中断方面:XHR 用
.abort()立即终止底层连接;Fetch 使用AbortController发送信号,由浏览器在 fetch 内部监听signal.aborted并取消请求,语义更清晰,且可跨多个 fetch 共享同一 signal。
CORS 与凭证处理的默认行为不一致
XHR 默认不携带 cookies 和认证头(withCredentials = false),需显式设置才启用凭证传递;而 Fetch 默认 credentials: 'same-origin',即同源请求自动带 cookie,跨域则不带——更贴近现代安全直觉。若需跨域传凭据,Fetch 必须显式写 credentials: 'include',且服务端必须返回 Access-Control-Allow-Credentials: true,否则被浏览器拦截。
另外,Fetch 的 mode(如 'cors'、'no-cors'、'same-origin')直接映射到 Fetch 标准定义的请求模式,影响预检、响应可读性等;XHR 没有对应概念,其 CORS 行为隐式由请求头和 origin 自动触发。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











