开发者
前端网络请求的双雄:XHR 与 Fetch API 深度解析
前端网络请求的双雄:XHR 与 Fetch API 深度解析
发表于2025/12/16
1020

在前端开发中,异步与服务器交互是实现动态页面的核心能力,XMLHttpRequest(XHR) 和 Fetch API 是实现该能力的两大核心工具。本教程将从基础使用、核心差异、实战选择三个维度,带大家掌握这两种工具的用法,助力实际项目开发。​

一、XHR:老牌请求工具的实操指南​

XHR 是浏览器原生 API,自 1999 年 IE5 引入后,长期支撑老旧项目的异步请求需求。它的优势是能精细控制请求全流程,下面通过完整代码示例,讲解其核心使用步骤。​

1.1 XHR 基础使用步骤(以 GET 请求为例)​

步骤 1:创建 XHR 实例​

通过 new XMLHttpRequest() 创建请求对象,这是发起请求的基础:​

// 1. 创建 XHR 实例​

const xhr = new XMLHttpRequest();​

步骤 2:配置请求参数(open 方法)​

使用 open(method, url, async) 定义请求类型、地址和是否异步(默认 true 异步):​

// 2. 配置请求:GET 方法,请求地址,异步模式​

步骤 3:设置请求头(可选)​

若服务器需要特定请求头(如数据格式、身份验证),用 setRequestHeader(key, value) 配置:​

步骤 4:监听请求状态变化(onreadystatechange)​

通过 onreadystatechange 事件监控请求进度,readyState 表示请求状态,status 表示 HTTP 状态码(200-299 为成功):

// 4. 监听请求状态变化,处理响应​

xhr.onreadystatechange = function() {​

 // readyState === 4 表示请求已完成,status === 200 表示请求成功​

 if (xhr.readyState === 4 && xhr.status >= 200 && xhr.status ) {​

 // 解析响应数据(根据服务器返回格式选择 responseText 或 responseXML)​

 const responseData = JSON.parse(xhr.responseText);​

 console.log('请求成功,数据:', responseData);​

 } else if (xhr.readyState === 4) {​

 // 请求完成但失败(如 404、500)​

 console.error('请求失败,状态码:', xhr.status);​

 }​

};​

步骤 5:发送请求(send 方法)

调用 send(body) 发送请求,GET 请求无需传参(传 null 即可),POST 请求需传入请求体:

// 5. 发送请求(GET 请求传 null)​

xhr.send(null);​

1.2 XHR 进阶功能(实战常用)

(1)监控上传 / 下载进度(onprogress)

通过 onprogress 事件实现进度条功能,适用于大文件上传 / 下载:

// 下载进度(服务器返回数据时触发)​

xhr.onprogress = function(e) {​

 if (e.lengthComputable) {​

 // 进度百分比 = 已加载字节 / 总字节 * 100​

 const progress = (e.loaded / e.total) * 100;​

 console.log('下载进度:', progress.toFixed(2) + '%');​

 // 可同步更新页面进度条 DOM​

 // document.getElementById('progress').style.width = progress + '%';​

 }​

};​

// 上传进度(仅 POST/PUT 等带请求体的方法生效)​

xhr.upload.onprogress = function(e) {​

 if (e.lengthComputable) {​

 const progress = (e.loaded / e.total) * 100;​

(2)中断请求(abort 方法)

若需取消正在进行的请求(如用户关闭弹窗),调用 abort() 即可:

// 示例:3 秒后中断请求​

setTimeout(() => {​

 xhr.abort();​

 console.log('请求已中断');​

}, 3000);​

1.3 XHR 优缺点总结

  • 优点:兼容性好(支持所有老旧浏览器)、支持进度监听和请求中断、可精细控制请求头。
  • 缺点:基于事件回调,复杂逻辑易陷入 “回调地狱”(如多个请求依赖时)、代码冗余。

二、Fetch API:现代请求方案的实操指南

Fetch API 是 ES6 新增的现代方案,基于 Promise 实现,代码更简洁,支持流式处理。下面通过实战代码,讲解其基础用法和注意事项。

2.1 Fetch 基础使用步骤(以 GET 请求为例)

步骤 1:调用 fetch 方法发起请求

fetch(url, options) 接收两个参数:请求地址和配置对象(可选),返回 Promise 对象:

 .then(response => {​

 // 步骤 2:判断请求是否成功(response.ok 等价于 status 200-299)

 if (!response.ok) {​

 // 手动抛出错误,进入 catch 环节

 throw new Error(`请求失败,状态码:${response.status}`);​

 }​

 // 步骤 3:解析响应数据(根据格式选择 json()/text()/blob())

 return response.json(); // 解析为 JSON 格式,返回 Promise

 })​

 .then(data => {​

 // 步骤 4:处理解析后的数据

 console.log('请求成功,数据:', data);​

 })​

 .catch(error => {​

 // 步骤 5:捕获错误(仅网络错误或手动抛出的错误)

 console.error('请求异常:', error.message);​

 });​

2.2 Fetch 进阶配置(POST 请求 + 自定义参数)

若需发起 POST 请求、携带 Cookie 或自定义请求头,需在 options 中配置:

fetch('https://api.example.com/submit', {​

 method: 'POST', // 请求方法:GET/POST/PUT/DELETE 等​

 headers: {​

 'Content-Type': 'application/json', // 数据格式​

 'Authorization': 'Bearer your-token' // 身份验证​

 },​

 credentials: 'include', // 携带 Cookie(same-origin 仅同域,include 跨域也携带)​

 body: JSON.stringify({ name: '张三', age: 20 }) // 请求体(需转为 JSON 字符串)​

})​

.then(response => {​

 if (!response.ok) throw new Error('提交失败');​

 return response.text(); // 解析为文本格式​

})​

.then(result => console.log('提交成功:', result))​

.catch(error => console.error('提交异常:', error));​

2.3 Fetch 关键注意事项(避坑指南)

  1. 错误处理逻辑:仅网络错误(如断网、域名无效)会触发 catch,4xx/5xx 状态码需通过 response.ok 手动判断。
  2. Cookie 携带:默认不携带 Cookie,需手动设置 credentials: 'include' 或 'same-origin'。
  3. 流式响应处理:支持分段处理大文件,示例如下:

fetch('https://api.example.com/large-file')​

 .then(response => {​

 // 获取响应流的读取器

 const reader = response.body.getReader();​

 // 循环读取数据块

 const readChunk = async () => {​

 const { done, value } = await reader.read();​

 if (done) {​

 console.log('文件读取完成');​

 return;​

 }​

 // 处理当前数据块(如写入本地缓存)

 console.log('读取数据块大小:', value.length);​

 readChunk(); // 继续读取下一块

 };​

 readChunk();​

 });​

三、XHR 与 Fetch API 核心差异对比(表格版)

对比维度​XHR​FetchAPI​
核心类型​XMLHttpRequest实例对象​Promise对象​
异步处理方式​事件回调(如onreadystatechange)​Promise链式调用(then/catch/finally)​
请求中断​直接调用abort() 方法​原生不支持,需结合AbortController
进度监听​支持onprogress/upload.onprogress原生不支持,需借助第三方库或流式处理​
响应解析​通过responseType自动解析(如 'json')​手动调用 json()/text()/blob()
Cookie 处理​默认自动携带同域Cookie​默认不携带,需配置credentials
错误触发条件​4xx/5xx状态码需手动判断​仅网络错误触发 reject,4xx/5xx需手动抛错​
跨域支持​需配置 withCredentials,支持JSONP​自动遵循CORS,不支持JSONP​
代码简洁度​代码冗余,嵌套多​代码简洁,逻辑线性​
浏览器兼容性​支持IE及所有现代浏览器​仅支持现代浏览器(IE不兼容)​

四、实战选择指南(按场景匹配)

4.1 优先选 XHR 的场景

  1. 维护老旧项目:需兼容 IE 浏览器或低版本 Chrome/Firefox。
  2. 需精细控制请求:如监控上传 / 下载进度、随时中断请求(无需额外代码)。
  3. 依赖 JSONP 跨域:部分老接口仅支持 JSONP,Fetch 不兼容该方案。

4.2 优先选 Fetch API 的场景

  1. 开发新项目:目标浏览器为现代浏览器(如 Chrome 60+、Firefox 55+)。
  2. 处理大文件:需流式读取数据(如视频分段加载、大文件上传)。
  3. 追求代码简洁:希望减少回调嵌套,用 Promise 简化异步逻辑。

4.3 推荐使用封装库(提升效率)

实际开发中,直接使用原生 API 可能需要处理兼容和异常,推荐使用成熟的封装库:

  • 基于 XHR 的库:Axios(支持拦截器、请求取消、自动转换 JSON,兼容性好)。
  • 基于 Fetch 的库:node-fetch(浏览器 / Node.js 通用)、whatwg-fetch(补足 Fetch 兼容性)
收藏举报
Level 1
0
帖子
0
粉丝
0
获赞