【Web API系列】XMLHttpRequest API和Fetch API深入理解与应用指南

news2025/4/12 20:57:46

在这里插入图片描述


前言

在现代Web开发中,客户端与服务器之间的异步通信是构建动态应用的核心能力。无论是传统的AJAX技术(基于XMLHttpRequest)还是现代的Fetch API,它们都为实现这一目标提供了关键支持。本文将从底层原理、核心功能、代码实践到实际应用场景,系统性地对比和分析这两种API的异同,帮助你掌握如何在不同场景下选择最佳解决方案。


文章目录

  • 前言
  • 一、XMLHttpRequest API:传统异步请求的基石
    • 1.1 核心概念与工作原理
    • 1.2 关键功能与高级用法
    • 1.3 局限性分析
  • 二、Fetch API:现代Web请求的标准方案
    • 2.1 设计理念与核心优势
    • 2.2 基础用法与代码示例
    • 2.3 高级功能实践
    • 2.4 常见问题与解决方案
  • 三、XMLHttpRequest与Fetch API的深度对比
    • 3.1 功能特性对比
    • 3.2 性能与适用场景
  • 四、实战案例:构建一个健壮的HTTP客户端
    • 4.1 基于Fetch的封装库
    • 4.2 实现文件分片上传
  • 总结


一、XMLHttpRequest API:传统异步请求的基石

1.1 核心概念与工作原理

XMLHttpRequest(XHR)是浏览器提供的原生API,用于在不刷新页面的情况下与服务器交换数据。其核心流程包括:

  1. 实例化对象:通过构造函数创建XMLHttpRequest实例。
  2. 配置请求:指定HTTP方法、URL及是否异步。
  3. 绑定事件:监听请求状态变化(如onloadonerror)。
  4. 发送请求:调用send()方法并处理响应数据。
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/data', true);
xhr.onload = function() {
  if (xhr.status === 200) {
    console.log(JSON.parse(xhr.responseText));
  } else {
    console.error('请求失败:', xhr.status);
  }
};
xhr.onerror = function() {
  console.error('网络错误');
};
xhr.send();

1.2 关键功能与高级用法

  • 同步与异步模式

    // 同步请求(阻塞主线程,不推荐)
    xhr.open('GET', 'https://api.example.com/data', false);
    xhr.send();
    console.log(xhr.responseText);
    
  • 处理二进制数据

    xhr.responseType = 'arraybuffer';
    xhr.onload = function() {
      const buffer = xhr.response;
      // 处理二进制数据(如图像或文件)
    };
    
  • 上传进度监控

    xhr.upload.onprogress = function(event) {
      const percent = (event.loaded / event.total) * 100;
      console.log(`上传进度: ${percent}%`);
    };
    
  • 超时控制

    xhr.timeout = 5000; // 5秒超时
    xhr.ontimeout = function() {
      console.error('请求超时');
    };
    

1.3 局限性分析

  1. 回调地狱:事件监听机制导致代码嵌套复杂。
  2. 错误处理不统一:需手动检查HTTP状态码和网络错误。
  3. 不支持Promise:与现代异步编程模式不兼容。

二、Fetch API:现代Web请求的标准方案

2.1 设计理念与核心优势

Fetch API基于Promise设计,提供更简洁、灵活的请求方式,并天然支持以下特性:

  • 链式调用:避免回调嵌套。
  • Streams API集成:处理流式数据(如大文件下载)。
  • CORS与安全策略:默认不发送跨域Cookie,需显式配置。

2.2 基础用法与代码示例

fetch('https://api.example.com/data')
  .then(response => {
    if (!response.ok) throw new Error('HTTP错误');
    return response.json();
  })
  .then(data => console.log(data))
  .catch(error => console.error('请求失败:', error));

2.3 高级功能实践

  • 自定义请求头与模式

    fetch('https://api.example.com/data', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer token'
      },
      body: JSON.stringify({ key: 'value' }),
      mode: 'cors', // 跨域模式
      credentials: 'include' // 包含Cookie
    });
    
  • 中断请求(AbortController)

    const controller = new AbortController();
    setTimeout(() => controller.abort(), 5000);
    
    fetch('https://api.example.com/data', {
      signal: controller.signal
    }).catch(error => {
      if (error.name === 'AbortError') {
        console.log('请求被手动取消');
      }
    });
    
  • 流式数据处理

    fetch('https://api.example.com/large-file')
      .then(response => {
        const reader = response.body.getReader();
        return new ReadableStream({
          start(controller) {
            function push() {
              reader.read().then(({ done, value }) => {
                if (done) {
                  controller.close();
                  return;
                }
                controller.enqueue(value);
                push();
              });
            }
            push();
          }
        });
      })
      .then(stream => new Response(stream))
      .then(response => response.blob());
    

2.4 常见问题与解决方案

  • 错误处理优化

    async function fetchWithRetry(url, retries = 3) {
      for (let i = 0; i < retries; i++) {
        try {
          const response = await fetch(url);
          if (!response.ok) throw new Error('HTTP错误');
          return await response.json();
        } catch (error) {
          if (i === retries - 1) throw error;
          await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
        }
      }
    }
    
  • 超时封装

    function fetchWithTimeout(url, timeout = 5000) {
      return Promise.race([
        fetch(url),
        new Promise((_, reject) =>
          setTimeout(() => reject(new Error('请求超时')), timeout)
        )
      ]);
    }
    

三、XMLHttpRequest与Fetch API的深度对比

3.1 功能特性对比

特性XMLHttpRequestFetch API
Promise支持
请求取消是(abort())是(AbortController)
流式数据处理有限支持完全支持
CORS处理需手动配置默认安全策略
Service Worker不支持完全集成

3.2 性能与适用场景

  • XMLHttpRequest适用场景

    • 需要监控上传/下载进度。
    • 兼容旧版浏览器(如IE10及以下)。
  • Fetch API推荐场景

    • 现代Web应用开发。
    • 需要与Service Worker配合实现离线缓存。
    • 处理流式数据或大文件。

四、实战案例:构建一个健壮的HTTP客户端

4.1 基于Fetch的封装库

class HttpClient {
  constructor(baseURL, headers = {}) {
    this.baseURL = baseURL;
    this.headers = headers;
  }

  async request(endpoint, options = {}) {
    const url = `${this.baseURL}${endpoint}`;
    const response = await fetch(url, {
      ...options,
      headers: { ...this.headers, ...options.headers }
    });

    if (!response.ok) {
      const error = new Error(`HTTP ${response.status}`);
      error.response = response;
      throw error;
    }

    const contentType = response.headers.get('content-type');
    if (contentType?.includes('application/json')) {
      return response.json();
    }
    return response.text();
  }

  get(endpoint, params) {
    const query = new URLSearchParams(params).toString();
    return this.request(`${endpoint}?${query}`, { method: 'GET' });
  }

  post(endpoint, body) {
    return this.request(endpoint, {
      method: 'POST',
      body: JSON.stringify(body),
      headers: { 'Content-Type': 'application/json' }
    });
  }
}

// 使用示例
const api = new HttpClient('https://api.example.com', {
  Authorization: 'Bearer token'
});
api.get('/users', { page: 1 }).then(users => console.log(users));

4.2 实现文件分片上传

async function uploadFile(file, chunkSize = 1024 * 1024) {
  const totalChunks = Math.ceil(file.size / chunkSize);
  for (let i = 0; i < totalChunks; i++) {
    const start = i * chunkSize;
    const end = Math.min(start + chunkSize, file.size);
    const chunk = file.slice(start, end);

    const formData = new FormData();
    formData.append('file', chunk);
    formData.append('chunkIndex', i);
    formData.append('totalChunks', totalChunks);

    await fetch('/upload', {
      method: 'POST',
      body: formData
    });
  }
}

总结

XMLHttpRequest作为Web异步通信的奠基者,至今仍在特定场景下发挥作用,而Fetch API凭借其现代化的设计正在成为主流选择。开发者需要根据以下因素决策:

  1. 浏览器兼容性:如需支持旧版浏览器,XHR仍是必要选项。
  2. 功能需求:进度监控、请求取消等特性可能影响技术选型。
  3. 代码可维护性:Fetch的Promise链与async/await语法更易维护。

未来,随着Web Streams API和Service Worker的普及,Fetch API将在性能优化和离线体验领域展现更大潜力。建议在新项目中优先采用Fetch,同时保持对XHR原理的理解以应对遗留系统维护需求。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2333362.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ESP32开发入门:基于VSCode+PlatformIO环境搭建指南

前言 ESP32作为一款功能强大的物联网开发芯片&#xff0c;结合PlatformIO这一现代化嵌入式开发平台&#xff0c;可以大幅提升开发效率。本文将详细介绍如何在VSCode中搭建ESP32开发环境&#xff0c;并分享实用开发技巧。 一、环境安装&#xff08;Windows/macOS/Linux&#xf…

2025.4.13机器学习笔记:文献阅读

2025.4.13周报 题目信息摘要创新点网络架构实验结论不足以及展望 题目信息 题目&#xff1a; Physics-informed neural networks for inversion of river flow and geometry with shallow water model期刊&#xff1a; Physics of Fluids作者&#xff1a; Y. Ohara; D. Moteki…

编程助手fitten code使用说明(超详细)(vscode)

这两年 AI 发展迅猛&#xff0c;作为开发人员&#xff0c;我们总是追求更快、更高效的工作方式&#xff0c;AI 的出现可以说改变了很多人的编程方式。 AI 对我们来说就是一个可靠的编程助手&#xff0c;给我们提供了实时的建议和解决方&#xff0c;无论是快速修复错误、提升代…

Python自动化爬虫:Scrapy+APScheduler定时任务

在数据采集领域&#xff0c;定时爬取网页数据是一项常见需求。例如&#xff0c;新闻网站每日更新、电商价格监控、社交媒体舆情分析等场景&#xff0c;都需要定时执行爬虫任务。Python的Scrapy框架是强大的爬虫工具&#xff0c;而APScheduler则提供了灵活的任务调度功能。 一、…

技术分享|iTOP-RK3588开发板Ubuntu20系统旋转屏幕方案

iTOP-3588开发板采用瑞芯微RK3588处理器&#xff0c;是全新一代AloT高端应用芯片&#xff0c;采用8nmLP制程&#xff0c;搭载八核64位CPU&#xff0c;四核Cortex-A76和四核Cortex-A55架构&#xff0c;主频高达2.4GHz。是一款可用于互联网设备和其它数字多媒体的高性能产品。 在…

3.3.1 spdlog异步日志

文章目录 3.3.1 spdlog异步日志1. spdlog1. 日志作用2 .同步日志和异步日志区别 2. spdlog是什么下载命令&#xff1a;2. spdlog为什么高效3. spdlog特征5. spdlog输出控制6. 处理流程7. 文件io8.问题 2. 如何创建logger3. 如何创建sink4. 如何自定义格式化5. 如何创建异步日志…

Java 基础(4)—Java 对象布局及偏向锁、轻量锁、重量锁介绍

一、Java 对象内存布局 1、对象内存布局 一个对象在 Java 底层布局&#xff08;右半部分是数组连续的地址空间&#xff09;&#xff0c;如下图示&#xff1a; 总共有三部分总成&#xff1a; 1. 对象头&#xff1a;储对象的元数据&#xff0c;如哈希码、GC 分代年龄、锁状态…

【AI论文】OLMoTrace:将语言模型输出追溯到万亿个训练标记

摘要&#xff1a;我们提出了OLMoTrace&#xff0c;这是第一个将语言模型的输出实时追溯到其完整的、数万亿标记的训练数据的系统。 OLMoTrace在语言模型输出段和训练文本语料库中的文档之间找到并显示逐字匹配。 我们的系统由扩展版本的infini-gram&#xff08;Liu等人&#xf…

SAP GUI 显示SAP UI5应用,并实现SSO统一登陆

想用SAP UI5 做一写界面&#xff0c;又不想给用户用标准的Fiori APP怎么办&#xff1f;我觉得可以用可配置物料标准功能的思路&#xff0c;在SAP GUI中显示UI5界面&#xff0c;而不是跳转到浏览器。 代码实现后的效果如下&#xff1a; 1、调用UI5应用&#xff0c;适用于自开发…

HumanDil-Ox-LDL:保存:2-8℃保存,避免强光直射,不可冻存

化学试剂的基本介绍&#xff1a; /// 英文名称&#xff1a;HumanDil-Oxidized LowDensityLipoprotein /// 中文名称&#xff1a;人源红色荧光标记氧化型低密度脂蛋白 /// 浓度&#xff1a;1.0-4.0 mg/ml /// 外观&#xff1a;乳状液体 /// 缓冲液组分&#xff1a;PBS&…

开箱即用!推荐一款Python开源项目:DashGo,支持定制改造为测试平台!

大家好&#xff0c;我是狂师。 市面上的开源后台管理系统项目层出不穷&#xff0c;对应所使用到的技术栈也不尽相同。 今天给大家推荐一款开源后台管理系统: DashGo&#xff0c;不仅部署起来非常的简单&#xff0c;而且它是基于Python技术栈实现的&#xff0c;使得基于它进行…

JS小练习0.1——弹出姓名

分析&#xff1a;1.用户输入 2.内部处理保存数据 3.打印输出 <body><script>let name prompt(输入你的名字)document.write(name)</script> </body>

vue自定义颜色选择器

vue自定义颜色选择器 效果图&#xff1a; step0: 默认写法 调用系统自带的颜色选择器 <input type"color">step1:C:\Users\wangrusheng\PycharmProjects\untitled18\src\views\Home.vue <template><div class"container"><!-- 颜…

LibreOffice Writer使用01去除单词拼写判断的红色下划线

这个软件还是非常有特色的&#xff0c;因为大家需要office的全部功能&#xff0c;常常忽略了这个软件的使用体验。 csdn不是特别稳定&#xff0c;linux也没有什么比较好的md编辑器&#xff0c;所以我选择这个软件来记录我的临时博客&#xff0c;原因无他&#xff0c;它可以保存…

0401react中使用css-react-css-仿低代码平台项目

文章目录 1、普通方式-内联使用css2、引入css文件2.1、示例2.2、classnames 3、内联css与引入css文件对比3.1、内联css3.2、 外部 CSS 文件&#xff08;External CSS&#xff09; 4、css module5、sass6、classnames组合scss modules7、css-in-js7.1、CSS-in-JS 的核心特性7.2、…

《线性表、顺序表与链表》教案(C语言版本)

&#x1f31f; 各位看官好&#xff0c;我是maomi_9526&#xff01; &#x1f30d; 种一棵树最好是十年前&#xff0c;其次是现在&#xff01; &#x1f680; 今天来学习C语言的相关知识。 &#x1f44d; 如果觉得这篇文章有帮助&#xff0c;欢迎您一键三连&#xff0c;分享给更…

[ctfshow web入门] web33

信息收集 相较于上一题&#xff0c;这题多了双引号的过滤。我猜测这一题的主要目的可能是为了不让使用$_GET[a]之类的语句&#xff0c;但是$_GET[a]也是一样的 没有括号可以使用include&#xff0c;没有引号可以使用$_GET 可以参考[ctfshow web入门] web32&#xff0c;其中的所…

三、TorchRec中的Optimizer

TorchRec中的Optimizer 文章目录 TorchRec中的Optimizer前言一、嵌入后向传递与稀疏优化器融合如下图所示&#xff1a;二、上述图片的关键步骤讲解&#xff1a;三、优势四、与传统优化器对比总结 前言 TorchRec 模块提供了一个无缝 API&#xff0c;用于在训练中融合后向传递和…

webrtc pacer模块(一) 平滑处理的实现

Pacer起到平滑码率的作用&#xff0c;使发送到网络上的码率稳定。如下的这张创建Pacer的流程图&#xff0c;其中PacerSender就是Pacer&#xff0c;其中PacerSender就是Pacer。这篇文章介绍它的核心子类PacingController及Periodic模式下平滑处理的基本流程。平滑处理流程中还有…