当前位置: 首页 > news >正文

【JavaScript-Day 48】告别 Ajax,拥抱现代网络请求:Fetch API 完全指南

Langchain系列文章目录

01-玩转LangChain:从模型调用到Prompt模板与输出解析的完整指南
02-玩转 LangChain Memory 模块:四种记忆类型详解及应用场景全覆盖
03-全面掌握 LangChain:从核心链条构建到动态任务分配的实战指南
04-玩转 LangChain:从文档加载到高效问答系统构建的全程实战
05-玩转 LangChain:深度评估问答系统的三种高效方法(示例生成、手动评估与LLM辅助评估)
06-从 0 到 1 掌握 LangChain Agents:自定义工具 + LLM 打造智能工作流!
07-【深度解析】从GPT-1到GPT-4:ChatGPT背后的核心原理全揭秘
08-【万字长文】MCP深度解析:打通AI与世界的“USB-C”,模型上下文协议原理、实践与未来

Python系列文章目录

PyTorch系列文章目录

机器学习系列文章目录

深度学习系列文章目录

Java系列文章目录

JavaScript系列文章目录

01-【JavaScript-Day 1】从零开始:全面了解 JavaScript 是什么、为什么学以及它与 Java 的区别
02-【JavaScript-Day 2】开启 JS 之旅:从浏览器控制台到 <script> 标签的 Hello World 实践
03-【JavaScript-Day 3】掌握JS语法规则:语句、分号、注释与大小写敏感详解
04-【JavaScript-Day 4】var 完全指南:掌握变量声明、作用域及提升
05-【JavaScript-Day 5】告别 var 陷阱:深入理解 letconst 的妙用
06-【JavaScript-Day 6】从零到精通:JavaScript 原始类型 String, Number, Boolean, Null, Undefined, Symbol, BigInt 详解
07-【JavaScript-Day 7】全面解析 Number 与 String:JS 数据核心操作指南
08-【JavaScript-Day 8】告别混淆:一文彻底搞懂 JavaScript 的 Boolean、null 和 undefined
09-【JavaScript-Day 9】从基础到进阶:掌握 JavaScript 核心运算符之算术与赋值篇
10-【JavaScript-Day 10】掌握代码决策核心:详解比较、逻辑与三元运算符
11-【JavaScript-Day 11】避坑指南!深入理解JavaScript隐式和显式类型转换
12-【JavaScript-Day 12】掌握程序流程:深入解析 if…else 条件语句
13-【JavaScript-Day 13】告别冗长if-else:精通switch语句,让代码清爽高效!
14-【JavaScript-Day 14】玩转 for 循环:从基础语法到遍历数组实战
15-【JavaScript-Day 15】深入解析 while 与 do…while 循环:满足条件的重复执行
16-【JavaScript-Day 16】函数探秘:代码复用的基石——声明、表达式与调用详解
17-【JavaScript-Day 17】函数的核心出口:深入解析 return 语句的奥秘
18-【JavaScript-Day 18】揭秘变量的“隐形边界”:深入理解全局与函数作用域
19-【JavaScript-Day 19】深入理解 JavaScript 作用域:块级、词法及 Hoisting 机制
20-【JavaScript-Day 20】揭秘函数的“记忆”:深入浅出理解闭包(Closure)
21-【JavaScript-Day 21】闭包实战:从模块化到内存管理,高级技巧全解析
22-【JavaScript-Day 22】告别 function 关键字?ES6 箭头函数 (=>) 深度解析
23-【JavaScript-Day 23】告别繁琐的参数处理:玩转 ES6 默认参数与剩余参数
24-【JavaScript-Day 24】从零到一,精通 JavaScript 对象:创建、访问与操作
25-【JavaScript-Day 25】深入探索:使用 for...in 循环遍历 JavaScript 对象属性
26-【JavaScript-Day 26】零基础掌握JavaScript数组:轻松理解创建、索引、长度和多维结构
27-【JavaScript-Day 27】玩转数组:push, pop, slice, splice 等方法详解与实战
28-【JavaScript-Day 28】告别繁琐循环:forEach, map, filter 数组遍历三剑客详解
29-【JavaScript-Day 29】数组迭代进阶:掌握 reduce、find、some 等高阶遍历方法
30-【JavaScript-Day 30】ES6新特性:Set与Map,让你的数据管理更高效!
31-【JavaScript-Day 31】对象的“蓝图”详解:构造函数、newinstanceof 完全指南
32-【JavaScript-Day 32】深入理解 prototype、__proto__ 与原型链的奥秘
33-【JavaScript-Day 33】深入浅出 ES6 Class:从入门到精通面向对象新姿势
34-【JavaScript-Day 34】前后端数据交互的通用语:深入解析JSON
35-【JavaScript-Day 35】从 window 到 location,一文掌握浏览器对象模型 BOM
36-【JavaScript-Day 36】前端基石:深入理解 DOM 并精通五大元素选择器
37-【JavaScript-Day 37】在 DOM 树中“行走”:节点遍历
38-【JavaScript-Day 38】JS操控网页外观:从innerHTML到classList的全方位指南
39-【JavaScript-Day 39】从零到一,动态构建交互式网页的 DOM 节点操作秘籍
40-【JavaScript-Day 40】响应用户操作:事件监听与处理从入门到精通
41-【JavaScript-Day 41】JS 事件大全:click, keydown, submit, load 等常见事件详解与实战
42-【JavaScript-Day 42】深入解析事件冒泡与捕获:掌握事件委托的精髓
43-【JavaScript-Day 43】从单线程到事件循环:深入解析JS同步与异步核心机制
44-【JavaScript-Day 44】告别混乱:从回调函数到“回调地狱”的演进与解决方案
45-【JavaScript-Day 45】异步编程救星:深入解析 Promise 的状态、创建与链式调用
46-【JavaScript-Day 46】解锁 Promise 并发控制:深入解析 Promise.all、race 与 allSettled
47-【JavaScript-Day 47】告别 .then 链:用 async/await 写出诗一样的异步代码
48-【JavaScript-Day 48】告别 Ajax,拥抱现代网络请求:Fetch API 完全指南


文章目录

  • Langchain系列文章目录
  • Python系列文章目录
  • PyTorch系列文章目录
  • 机器学习系列文章目录
  • 深度学习系列文章目录
  • Java系列文章目录
  • JavaScript系列文章目录
  • 前言
  • 一、Fetch API 概述
    • 1.1 什么是 Fetch API?
    • 1.2 Fetch API vs. XMLHttpRequest (XHR)
    • 1.3 基本语法结构
  • 二、发起 GET 请求
    • 2.1 最简单的 GET 请求
    • 2.2 解读 Response 对象
    • 2.3 解析响应数据
    • 2.4 结合 async/await 使用
  • 三、发起 POST 请求
    • 3.1 POST 请求的核心:`options` 对象
    • 3.2 设置请求方法和头部
    • 3.3 准备请求体 `body`
    • 3.4 完整的 POST 请求示例
  • 四、Fetch 中的错误处理
    • 4.1 Fetch 的“奇怪”行为
    • 4.2 如何正确处理 HTTP 错误
  • 五、总结


前言

在上一篇文章中,我们学习了 async/await,它为我们处理异步操作提供了终极的、如同同步代码般优雅的解决方案。现在,是时候将这项强大的技能应用到 Web 开发最核心的场景之一:与服务器进行数据交换了。过去,这项任务主要由 XMLHttpRequest (XHR) 对象承担,但其设计复杂、基于事件的模式在现代 JavaScript 中显得有些格格不入。

今天,我们将隆重介绍现代 Web 的标准网络请求工具——Fetch API。它是一个基于 Promise 的强大接口,能够让我们以更简洁、更直观、更强大的方式发送网络请求和处理响应。本文将带你从零开始,全面掌握 Fetch API 的使用,无论是获取数据(GET)还是提交数据(POST),你都能轻松应对。

一、Fetch API 概述

在深入代码之前,我们首先需要理解 Fetch API 是什么,以及它相较于传统方法的优势所在。

1.1 什么是 Fetch API?

Fetch API 提供了一个 JavaScript 接口,用于访问和操纵 HTTP 管道的部分,例如请求和响应。它还提供了一个全局的 fetch() 方法,该方法提供了一种简单、合理的方式来跨网络异步获取资源。

这个 fetch() 方法被设计为现代、通用的网络请求工具,它天生基于 Promise,这使得它能够完美地与我们之前学习的 async/await 语法结合,编写出既强大又易于阅读的异步代码。

其核心特性可以总结为:

  • 现代性:作为 XMLHttpRequest 的替代者,旨在简化网络请求。
  • Promise 驱动fetch() 返回一个 Promise 对象,让异步处理更加链式化和直观。
  • 功能强大:提供了丰富的 RequestResponse 对象,可以对请求和响应进行精细化控制。
  • 全局可用fetch() 方法存在于 windowworker 的全局作用域中,无需引入任何库即可使用。

1.2 Fetch API vs. XMLHttpRequest (XHR)

为了更好地理解 Fetch 的优势,我们可以将其与传统的 XMLHttpRequest (XHR) 进行一个简单的对比。

特性XMLHttpRequest (XHR)Fetch API
核心机制基于事件和回调函数基于 Promise
语法相对冗长和复杂,需要实例化对象并监听事件语法简洁,一个函数调用即可发起请求
API 设计API 设计较为分散,配置和状态通过不同属性和方法管理API 设计更聚合,通过 RequestResponse 对象进行统一管理
可读性容易陷入“回调地狱”完美结合 Promise 链式调用和 async/await,代码清晰
错误处理通过 onerror 事件处理网络层错误,HTTP 状态码需在 onreadystatechange 中判断仅在网络失败时 reject,HTTP 错误状态(如 404, 500)需在 then 中手动检查

很明显,Fetch API 在语法和设计理念上都更符合现代 JavaScript 的开发模式。

1.3 基本语法结构

fetch() 方法的语法非常简单,它接受一个必需参数(资源路径)和一个可选参数(配置对象)。

fetch(resource, options).then(response => {// 处理响应对象 (Response)}).catch(error => {// 处理网络错误});
  • resource: 你想要请求的资源 URL。这通常是一个字符串。
  • options (可选): 一个配置对象,允许你控制请求的各个方面,如请求方法 (method)、请求头 (headers)、请求体 (body) 等。如果省略,默认为 GET 请求。

这个流程图揭示了一个关键点:fetch() 是一个两步过程。首先,它返回一个代表响应的 Response 对象;然后,你需要使用 Response 对象的方法来真正地解析响应体中的数据。

二、发起 GET 请求

GET 请求是最常见的网络请求类型,用于从服务器获取数据。使用 fetch 发起 GET 请求非常直接。

2.1 最简单的 GET 请求

当不提供 options 对象或 options.method 未指定时,fetch 默认执行 GET 请求。

// 示例:从 JSONPlaceholder 获取一篇博文
fetch('https://jsonplaceholder.typicode.com/posts/1').then(response => response.json()) // 第一步:解析响应体为 JSON.then(data => console.log(data))   // 第二步:获取并使用最终数据.catch(error => console.error('请求失败:', error));

在这个例子中:

  1. 我们向指定的 URL 发送了一个 GET 请求。
  2. 第一个 .then() 接收到一个 Response 对象。我们调用它的 .json() 方法,这个方法会读取响应体并尝试将其解析为 JSON。重要的是,.json() 方法本身也返回一个 Promise。
  3. 第二个 .then().json() 的 Promise 完成后执行,接收到最终解析出的 JavaScript 对象,并将其打印到控制台。
  4. .catch() 用于捕获在整个过程中可能发生的网络错误(例如,DNS 解析失败、用户离线)。

2.2 解读 Response 对象

在调用 .json().text() 之前,我们得到的 Response 对象本身包含了大量关于响应的有用信息。

属性类型描述
okBoolean一个布尔值,表示请求是否成功。HTTP 状态码在 200-299 范围内为 true
statusNumberHTTP 响应的状态码,例如 200 表示成功,404 表示未找到。
statusTextString状态码对应的文本信息,例如 “OK” 或 “Not Found”。
headersHeaders一个 Headers 对象,允许你查询响应头信息。
urlString请求的完整 URL。

检查 response.ok 是处理请求的良好实践,我们将在错误处理部分详细讨论。

fetch('https://jsonplaceholder.typicode.com/posts/1').then(response => {console.log('请求成功!');console.log('状态码:', response.status);       // 输出: 200console.log('状态文本:', response.statusText);   // 输出: OKconsole.log('响应是否成功:', response.ok);     // 输出: trueconsole.log('Content-Type 头:', response.headers.get('content-type')); // 输出: application/json; charset=utf-8return response.json();}).then(data => {console.log('获取到的数据:', data);});

2.3 解析响应数据

Response 对象提供了多种方法来处理不同格式的响应体,它们都返回 Promise。

  • response.json(): 解析响应体为 JSON 对象。
  • response.text(): 解析响应体为纯文本。
  • response.blob(): 解析响应体为 Blob 对象,用于处理图片、文件等二进制数据。
  • response.formData(): 解析响应体为 FormData 对象。
  • response.arrayBuffer(): 解析响应体为 ArrayBuffer 对象,用于处理通用的、固定长度的原始二进制数据。

2.4 结合 async/await 使用

使用 async/await 可以让 fetch 调用看起来更像同步代码,从而极大地提升了可读性。

// 使用 async/await 重写上面的 GET 请求
async function getPostData(postId) {try {// 等待 fetch 请求完成,获取 Response 对象const response = await fetch(`https://jsonplaceholder.typicode.com/posts/${postId}`);// 检查响应是否成功if (!response.ok) {// 如果不成功,手动抛出错误throw new Error(`HTTP 错误! 状态: ${response.status}`);}// 等待响应体解析为 JSONconst data = await response.json();console.log(data);} catch (error) {// 捕获网络错误或我们手动抛出的错误console.error('获取数据失败:', error);}
}getPostData(1);

这段代码的功能与之前的 .then 链版本完全相同,但逻辑更清晰、更易于调试。

三、发起 POST 请求

POST 请求用于向服务器提交数据,通常用于创建新资源。这需要我们使用 fetch 的第二个参数——options 对象。

3.1 POST 请求的核心:options 对象

要发送 POST 请求,我们至少需要配置 method, headers, 和 body 这三个关键属性。

  • method: HTTP 请求方法,设置为 'POST'
  • headers: 一个包含请求头的对象。对于发送 JSON 数据的场景,必须设置 'Content-Type': 'application/json',以告知服务器我们发送的是 JSON 格式的数据。
  • body: 请求的主体内容。注意:body 必须是一个字符串,因此我们需要使用 JSON.stringify() 将 JavaScript 对象转换为 JSON 字符串。

3.2 设置请求方法和头部

const options = {method: 'POST', // 指定请求方法为 POSTheaders: {'Content-Type': 'application/json', // 告诉服务器,我们发送的是 JSON 数据// 'Authorization': 'Bearer YOUR_TOKEN' // 如果需要认证,可以在这里添加},// ... 后面会添加 body
};

3.3 准备请求体 body

假设我们要创建一个新的博文对象,首先定义这个对象,然后使用 JSON.stringify() 将其转换。

// 1. 定义要发送的 JavaScript 对象
const newPost = {title: '一篇关于 Fetch 的新文章',body: 'Fetch API 非常强大和灵活。',userId: 1,
};// 2. 将对象转换为 JSON 字符串
const requestBody = JSON.stringify(newPost);

3.4 完整的 POST 请求示例

现在,我们将所有部分组合起来,构建一个完整的 POST 请求。

async function createPost() {const newPostData = {title: '学习 Fetch API',body: '使用 async/await 发送 POST 请求。',userId: 10,};try {const response = await fetch('https://jsonplaceholder.typicode.com/posts', {method: 'POST', // 请求方法headers: {'Content-Type': 'application/json', // 请求头},body: JSON.stringify(newPostData), // 请求体});if (!response.ok) {throw new Error(`HTTP 错误! 状态: ${response.status}`);}// 服务器通常会返回新创建的资源(带有一个 id)const createdPost = await response.json();console.log('成功创建资源:', createdPost);// 预期的输出可能像这样: { id: 101, title: '...', body: '...', userId: 10 }} catch (error) {console.error('创建帖子失败:', error);}
}createPost();

这个例子清晰地展示了如何配置并发送一个 POST 请求,并处理服务器的响应。

四、Fetch 中的错误处理

错误处理是健壮应用程序的关键部分,而 fetch 的错误处理机制有一个非常重要的特点需要我们特别注意。

4.1 Fetch 的“奇怪”行为

一个常见的误区是:认为所有非 2xx 的 HTTP 状态(如 404 Not Found, 500 Internal Server Error)都会导致 fetch 的 Promise被 reject

事实并非如此。

fetch() 返回的 Promise 仅在遇到网络级别故障时(例如,无法连接服务器、CORS 策略阻止了请求等)才会被 reject。对于服务器返回的任何 HTTP 状态码(包括 4xx 和 5xx),fetch 的 Promise 都会被 fulfill(即成功解决),并返回一个 Response 对象。

这意味着,以下代码 无法 捕获到 404 错误:

// 错误示范:这样无法捕获到 404 错误
fetch('https://jsonplaceholder.typicode.com/posts/non-existent-url').then(response => response.json()) // 即使是 404,这里也会执行.then(data => console.log(data))   // 这里可能会因为 response.json() 失败而报错.catch(error => {// 这个 catch 块不会因为 404 而被触发console.error('这个 catch 不会捕获到 404 错误', error);});

4.2 如何正确处理 HTTP 错误

正确的做法是利用我们之前介绍的 response.ok 属性。这个属性为我们提供了一个简单的方式来判断 HTTP 状态码是否在成功范围内(200-299)。

正确的错误处理模式如下:

  1. 发起 fetch 请求。
  2. 在第一个 .then()await 之后,检查 response.ok 的值。
  3. 如果 response.okfalse,则手动创建一个 Error 对象并 throw 它。
  4. 这样,这个被抛出的错误就可以被后续的 .catch() 块或 try...catch 语句捕获。
// 正确的错误处理模式
async function getPostDataSafely(postId) {try {const response = await fetch(`https://jsonplaceholder.typicode.com/posts/${postId}`);// 关键步骤:检查响应是否成功if (!response.ok) {// 如果不成功,构建一个包含状态码和文本的错误信息const errorText = await response.text(); // 尝试获取错误响应体throw new Error(`请求失败,状态码: ${response.status}. 响应: ${errorText}`);}const data = await response.json();console.log('获取数据成功:', data);} catch (error) {// 现在可以捕获所有类型的错误:网络错误和我们手动抛出的 HTTP 错误console.error('操作失败:', error.message);}
}// 测试一个存在的资源
getPostDataSafely(1);// 测试一个不存在的资源
getPostDataSafely(9999); // 将会触发 catch 块

通过这种模式,我们就能统一处理网络错误和应用层(HTTP)错误,让我们的代码更加健壮和可预测。

五、总结

Fetch API 是现代 JavaScript 中进行网络通信的基石。通过本文的学习,我们掌握了其核心用法和关键概念,现在让我们来回顾一下重点:

  1. 核心理念Fetch API 是一个基于 Promise 的现代网络请求接口,通过全局 fetch() 函数使用,它比传统的 XMLHttpRequest 更简洁、更强大。
  2. 两步处理fetch() 的调用是一个两阶段的过程。第一阶段是获取 Response 对象,它包含了响应的元数据(如状态码、头部)。第二阶段是调用 Response 对象的方法(如 .json(), .text())来异步解析响应体,获取真实数据。
  3. 请求配置:对于 GET 以外的请求(如 POST),我们需要使用 fetch() 的第二个参数 options 对象来详细配置请求,包括 methodheadersbody。特别注意 body 必须是字符串,通常使用 JSON.stringify() 进行转换。
  4. 关键的错误处理fetch 的 Promise 只在网络失败时 reject。对于服务器返回的 HTTP 错误状态(如 404, 500),Promise 依然会 fulfill。因此,必须在代码中显式检查 response.ok 属性,并手动抛出错误,才能被 .catch()try...catch 统一捕获。
  5. 最佳实践:结合 async/await 使用 fetch 可以让异步网络请求代码的结构变得扁平、清晰,是当前处理网络请求的最佳实践。

掌握了 Fetch API,你就掌握了与世界各地服务器对话的能力。在接下来的文章中,我们将学习如何组织我们的代码,使其更具可维护性和可重用性——欢迎来到模块化的世界!


相关文章:

  • 黄岛网站建设公司免费建站免费网站
  • 做网站卖狗挣钱吗营销公司排行
  • 自己做博客网站和百家号的区别微信软文推广怎么做
  • 做嫒嫒网站aso排名
  • 台州企业网站一元手游平台app
  • 网站中英文转换怎么做seo营销推广多少钱
  • HarmonyOS开发基础 --面向鸿蒙的TypeScript基础语法一文入门
  • 深度解析!MySQL 与 Oracle 执行计划的硬核对比与实战攻略
  • 从iOS到Flutter:我的转型之路与技术成长启示
  • 死锁_(上)
  • BI财务分析 – 反映盈利水平利润占比的指标如何分析(下)
  • 用 Python 打造立体数据世界:3D 堆叠条形图绘制全解析
  • 中科米堆3D扫描逆向建模方案:汽车轮毂三维扫描抄数建模
  • 国产化条码类库Spire.Barcode教程:如何使用 C# 读取 PDF 中的条码(两种方法轻松实现)
  • Modbus 扫描 从站号、波特率
  • 02-Linux内核源码编译
  • 【WCF】单例模式的线程安全缓存管理器实现,给你的WebApi加入缓存吧
  • 【网络安全】从IP头部看网络通信:IPv4、IPv6与抓包工具 Wireshark 实战
  • Leaflet面试题200道
  • 多光谱扫描技术在实物建模中的应用:如何实现1:1真实材质还原
  • OpenCV CUDA模块设备层-----检查 CUDA 错误并输出调试信息内联函数checkCudaError()
  • 网络安全攻防:2025年新型钓鱼攻击防御指南
  • 安卓android com.google.android.material.tabs.TabLayout 设置下拉图标无法正常显示
  • Rust 项目实战:单线程 Web 服务器
  • RabbitMQ + JMeter 深度集成指南:中间件性能优化全流程解析!
  • 国际数字影像产业园2.0:数字技术赋能影像文创的生态重构