Fetch API 使用及简单封装
Fetch API是现代浏览器提供的用于发起网络请求的原生 JavaScript API。它的设计初衷是替代老旧、基于回调的XMLHttpRequest(XHR)提供更强大、更灵活且基于Promise的异步编程体验。虽然 Fetch 已经成为现代前端的标配但它的设计存在一些“反直觉”的地方。以下是对 Fetch 的全面、详细说明。一、 基础用法Fetch 的核心是window.fetch()方法。它接收一个 URL 和一个可选的配置对象返回一个 Promise。1. GET 请求// 传统 Promise 写法 fetch(https://api.example.com/users) .then(response { // 注意response.json() 返回的依然是一个 Promise return response.json(); }) .then(data console.log(data)) .catch(error console.error(Error:, error)); // 现代 async/await 写法 (推荐) async function getUsers() { try { const response await fetch(https://api.example.com/users); const data await response.json(); console.log(data); } catch (error) { console.error(Error:, error); } }2. POST 请求POST 请求需要通过options参数配置method、headers和body。async function createUser() { const userData { name: 张三, age: 25 }; try { const response await fetch(https://api.example.com/users, { method: POST, headers: { Content-Type: application/json // 必须手动声明 JSON 格式 }, body: JSON.stringify(userData) // 必须手动将对象转为 JSON 字符串 }); const result await response.json(); console.log(Success:, result); } catch (error) { console.error(Error:, error); } }⚠️ 避坑指南 (FormData)如果你要上传文件使用了FormData对象作为body千万不要手动设置Content-Type。浏览器会自动将其设置为multipart/form-data并附带正确的boundary。如果你手动设置了反而会破坏 boundary导致后端无法解析文件。二、 响应处理 (Response 对象)fetchresolve 后返回的是一个Response对象它包含了服务器的响应头、状态码和响应体。1. 解析响应体响应体是流 (Stream)只能被读取一次。根据数据类型调用不同的方法response.json()解析为 JSON 对象最常用。response.text()解析为纯文本。response.blob()解析为二进制大对象常用于下载文件、图片预览。response.arrayBuffer()解析为原始二进制缓冲区常用于处理音频、视频流。2. 常用 Response 属性response.ok(Boolean)极其重要。当 HTTP 状态码在 200-299 之间时为true。response.status(Number)HTTP 状态码如 200, 404, 500。response.statusText(String)状态信息如 OK, Not Found。response.headers(Headers 对象)响应头可通过response.headers.get(Content-Type)获取。三、 Fetch 的四大“痛点”为什么我们需要封装尽管 Fetch 是原生 API但直接裸写 Fetch 往往会带来很多麻烦。以下是它的核心缺陷痛点 1HTTP 错误状态码4xx, 5xx不会触发catch这是新手最容易踩的坑。在 Fetch 的设计中只有网络故障如断网、DNS 解析失败、请求被拦截才会导致 Promise reject。 如果服务器返回了404 Not Found或500 Internal Server ErrorFetch 依然会正常 resolve进入then。fetch(/api/not-found) // 假设返回 404 .then(res { console.log(res.ok); // false console.log(res.status); // 404 // 注意这里不会进入 catch }) .catch(err { // 只有断网时才会进这里 });解决方案必须手动判断response.ok如果不为 true则手动抛出错误。痛点 2原生不支持超时控制XHR 可以通过xhr.timeout设置超时但 Fetch 原生没有这个属性。如果服务器一直不响应请求会无限期挂起。解决方案必须借助AbortController结合setTimeout手动实现如上一个回答中的封装。痛点 3默认不携带 Cookie (跨域时)在跨域请求时Fetch 默认不会携带目标域的 Cookie。解决方案需要显式设置credentials: include。fetch(https://api.other-domain.com/data, { credentials: include // 允许跨域携带 Cookie })痛点 4无法直接监听上传/下载进度XHR 提供了xhr.upload.onprogress和xhr.onprogress来轻松实现进度条。Fetch 没有直接的进度事件。解决方案下载进度可以通过ReadableStream模拟计算上传进度目前 Fetch 原生支持极差通常只能退回使用 XHR 或 Axios。四、 高级特性 (Fetch 的杀手锏)虽然 Fetch 有痛点但它提供了 XHR 无法比拟的现代特性1. 中断请求 (AbortController)这是 Fetch 最强大的特性之一可以轻松取消正在进行的请求例如用户快速切换页面或防抖取消上一次请求。const controller new AbortController(); const signal controller.signal; // 发起请求 fetch(https://api.example.com/slow-data, { signal }) .then(res res.json()) .then(data console.log(data)) .catch(err { if (err.name AbortError) { console.log(请求被手动取消); } else { console.error(请求失败, err); } }); // 3秒后取消请求 setTimeout(() { controller.abort(); // 触发取消 }, 3000);2. 流式读取 (ReadableStream)Fetch 允许你以流的方式分块读取响应体这在处理大文件下载或SSE (Server-Sent Events) 实时推送时非常有用不需要等整个文件下载完才开始处理。fetch(https://example.com/large-file.zip) .then(response { const reader response.body.getReader(); const contentLength response.headers.get(Content-Length); let receivedLength 0; let chunks []; return (async function read() { while(true) { const { done, value } await reader.read(); if (done) break; chunks.push(value); receivedLength value.length; console.log(下载进度: ${(receivedLength / contentLength * 100).toFixed(2)}%); } // 将所有块合并为一个 Blob let blob new Blob(chunks); console.log(下载完成, blob); })(); });五、 总结与最佳实践Fetch vs XMLHttpRequest vs Axios特性FetchXMLHttpRequest (XHR)Axios底层实现现代标准 API老旧 API浏览器端基于 XHRNode 端基于 httpPromise 支持原生支持不支持 (需手动封装)原生支持数据转换需手动 (res.json(),JSON.stringify)需手动自动转换 JSON超时控制需手动 (AbortController)原生支持 (timeout)原生支持 (timeout)进度监听极难 (需用 Stream 模拟)原生支持 (onprogress)原生支持拦截器无无支持 (请求/响应拦截)取消请求支持 (AbortController)支持 (abort())支持建议不要在业务代码中裸写 Fetch因为它的痛点太多状态码不报错、无超时、无自动 JSON 转换。中小型项目/简单脚本使用自定义 Fetch 封装类轻量且无第三方依赖。中大型商业项目建议使用Axios。它完美解决了 Fetch 的所有痛点提供了拦截器、自动转换、取消请求等工程化能力且生态极其成熟。特殊场景使用原生 Fetch当你需要处理流式数据 (SSE)、大文件分块下载或者在 Service Worker 中拦截请求时必须使用原生 Fetch。六、对Fetch简单封装由于原生fetch存在一些痛点如不支持超时控制、不自动转换 JSON、HTTP 4xx/5xx 不会进入 catch、GET 请求处理参数麻烦。这个封装解决了这些问题同时保持了代码的极简。主要说明自动超时中断利用AbortController实现了原生fetch缺失的超时控制防止请求无限挂起。智能参数处理GET请求自动将对象序列化为 URL Query 字符串POST/PUT自动将对象转换为 JSON 字符串。状态码校验原生fetch遇到 404 或 500 依然会进入then封装后统一在!response.ok时抛出异常进入catch符合直觉。智能响应解析自动检测Content-Type如果是 JSON 则自动调用.json()否则返回.text()避免解析报错。安全过滤拼接 URL 参数时自动过滤掉undefined和null的值避免产生?key这样的脏 URL// http.js /** * 轻量级 Fetch 请求封装 */ class Http { /** * param {string} baseURL - 基础请求地址 * param {object} defaultOptions - 默认配置如全局 headers、timeout */ constructor(baseURL , defaultOptions {}) { this.baseURL baseURL; this.defaultOptions { timeout: 10000, // 默认 10 秒超时 ...defaultOptions, }; } /** * 核心请求方法 * param {string} url - 请求路径 * param {object} options - 请求配置 { method, params, data, headers, timeout, ... } * returns {Promiseany} */ async request(url, options {}) { const { method GET, params, data, headers {}, timeout this.defaultOptions.timeout, ...rest } options; const upperMethod method.toUpperCase(); // 1. 拼接完整 URL 和 Query 参数 const fullUrl this._buildUrl(url, params); // 2. 合并 Headers (默认携带 application/json) const finalHeaders { Content-Type: application/json, ...this.defaultOptions.headers, ...headers, }; // 3. 构建 Fetch 选项 (GET/HEAD 请求不允许携带 body) const fetchOptions { method: upperMethod, headers: finalHeaders, ...rest, }; if (data ![GET, HEAD].includes(upperMethod)) { fetchOptions.body typeof data string ? data : JSON.stringify(data); } // 4. 超时控制 (使用 AbortController) const controller new AbortController(); const timeoutId setTimeout(() controller.abort(), timeout); fetchOptions.signal controller.signal; try { const response await fetch(fullUrl, fetchOptions); clearTimeout(timeoutId); // 5. 校验 HTTP 状态码 (fetch 只有在网络故障时才会 reject4xx/5xx 需要手动判断) if (!response.ok) { throw new Error(HTTP Error: ${response.status} ${response.statusText}); } // 6. 智能解析响应体 const contentType response.headers.get(content-type); if (contentType contentType.includes(application/json)) { return await response.json(); } return await response.text(); } catch (error) { clearTimeout(timeoutId); if (error.name AbortError) { throw new Error(Request Timeout); } // 这里可以统一接入全局错误提示 (如 Toast.error(error.message)) throw error; } } /** * 辅助方法拼接 URL 和 Query 参数 */ _buildUrl(url, params) { const targetUrl url.startsWith(http) ? url : this.baseURL url; if (!params) return targetUrl; const searchParams new URLSearchParams(); Object.keys(params).forEach(key { if (params[key] ! undefined params[key] ! null) { searchParams.append(key, params[key]); } }); const queryString searchParams.toString(); return queryString ? ${targetUrl}?${queryString} : targetUrl; } // 快捷方法 get(url, params {}, options {}) { return this.request(url, { ...options, method: GET, params }); } post(url, data {}, options {}) { return this.request(url, { ...options, method: POST, data }); } put(url, data {}, options {}) { return this.request(url, { ...options, method: PUT, data }); } delete(url, params {}, options {}) { // RESTful 风格中DELETE 有时带 params有时带 data这里默认支持 params return this.request(url, { ...options, method: DELETE, params }); } } // 导出 (支持 ES Modules 和 CommonJS) export default Http; // module.exports Http; // 如果是 CommonJS 环境取消此行注释1. 基础实例化与调用// 实例化配置全局基础 URL 和默认 Header (例如 Token) const api new Http(https://api.example.com/v1, { headers: { Authorization: Bearer YOUR_TOKEN_HERE }, timeout: 8000 // 全局默认 8 秒超时 }); // GET 请求 (自动拼接 ?id123typeuser) api.get(/users, { id: 123, type: user }) .then(res console.log(用户数据:, res)) .catch(err console.error(请求失败:, err.message)); // POST 请求 (自动 JSON.stringify body) api.post(/users, { name: 张三, age: 25 }) .then(res console.log(创建成功:, res)) .catch(err console.error(请求失败:, err.message));2. 临时覆盖默认配置// 某次请求需要不同的 Header 或更长的超时时间 api.post( /upload, { file: data }, { timeout: 30000, // 此次请求 30 秒超时 headers: { Content-Type: multipart/form-data } // 覆盖默认 Content-Type } );3. 在 HTML 中直接引入使用 (无需构建工具)!DOCTYPE html html langzh-CN head meta charsetUTF-8 titleFetch 封装示例/title !-- 引入 http.js文件 -- script src./http.js/script /head body button idbtn获取数据/button script typemodule // 假设 Http 类已在当前作用域定义 const api new Http(https://jsonplaceholder.typicode.com); document.getElementById(btn).addEventListener(click, async () { try { const data await api.get(/posts, { _limit: 1 }); console.log(获取成功:, data); alert(JSON.stringify(data)); } catch (error) { console.error(获取失败:, error.message); alert(请求失败: error.message); } }); /script /body /html

相关新闻

Linux内核源码高频面试题解析与实战技巧

Linux内核源码高频面试题解析与实战技巧

1. 项目背景与核心价值最近在整理技术面试资料时,发现Linux内核相关的源码分析题目一直是高级开发岗位的考察重点。这些题目不仅考察候选人对操作系统原理的理解深度,更能真实反映其系统级编程能力和问题排查思维。本文将分享12道高频Linux内核源码面试题…

2026/7/24 11:28:30阅读更多 →
2026动力传动洞察:四大系列减速机在工业自动化中的深层逻辑与选型重构

2026动力传动洞察:四大系列减速机在工业自动化中的深层逻辑与选型重构

在工业自动化领域,传动系统的选型从来不是简单的参数堆砌,而是一场关于效率、空间、成本与全生命周期可靠性的精密博弈。当我们谈论‘减速机’时,很多从业者往往陷入了唯品牌论或唯价格论的二元陷阱,忽略了负载特性和工况环境对传…

2026/7/24 11:28:30阅读更多 →
国产系统SSH免密登录配置与安全实践

国产系统SSH免密登录配置与安全实践

1. 项目背景与需求解析在企业级IT运维和开发者日常工作中,频繁登录服务器执行维护任务是常态。传统密码验证方式存在两大痛点:一是每次连接都需要手动输入密码,效率低下;二是密码泄露风险始终存在。特别是在国产操作系统生态中&am…

2026/7/24 11:28:30阅读更多 →
04-观点分析-2026年下半年数字孪生行业五大预测深度解析

04-观点分析-2026年下半年数字孪生行业五大预测深度解析

2026年下半年数字孪生行业五大预测:AI原生化、边缘计算、标准化突破 引言 2026年上半年,数字孪生行业经历了技术革新和市场洗牌的双重变革。AI大模型的爆发式应用、边缘计算的成熟部署、行业标准的逐步建立,都在深刻重塑行业格局。本文基于上…

2026/7/24 12:50:49阅读更多 →
GEO优化适合哪些行业?广拓时代谈AI搜索流量新入口

GEO优化适合哪些行业?广拓时代谈AI搜索流量新入口

很多企业一听到GEO优化,第一反应是:这是大企业才需要做的东西吗?普通公司有没有必要跟进? 其实判断一个行业适不适合做GEO,不看企业规模,而看客户决策方式。只要你的客户在成交前会搜索、会比较、会问“哪家…

2026/7/24 12:50:49阅读更多 →
AM5718-HIREL接口时序深度解析:从基础概念到PCB设计实战

AM5718-HIREL接口时序深度解析:从基础概念到PCB设计实战

1. 项目概述:为什么我们需要深究接口时序?在嵌入式硬件开发,尤其是基于复杂SoC(片上系统)的设计中,我们常常会陷入一个误区:只要原理图连接正确,软件驱动能跑起来,硬件设…

2026/7/24 12:50:49阅读更多 →
MedOS:AI与XR融合的智能手术系统实践

MedOS:AI与XR融合的智能手术系统实践

1. 项目背景与核心价值MedOS这篇论文提出了一种融合AI、扩展现实(XR)和协作机器人(Cobot)技术的临床世界模型,代表了医疗智能化领域的前沿探索。作为医疗多模态大模型(MLMs)的重要实践,它试图解决传统医疗系统中感知与行动割裂的痛点。我在临床智能化项目…

2026/7/24 12:50:49阅读更多 →
AWR1642毫米波雷达接口时序与电气特性深度解析:SPI、LVDS、CAN-FD实战指南

AWR1642毫米波雷达接口时序与电气特性深度解析:SPI、LVDS、CAN-FD实战指南

1. 项目概述:为什么接口时序是毫米波雷达设计的“生命线”在毫米波雷达这类高集成度、高性能的嵌入式系统中,芯片与外部世界沟通的桥梁——即各种高速数字接口——的稳定性和可靠性,直接决定了整个系统的成败。很多工程师在项目初期往往更关注…

2026/7/24 12:50:49阅读更多 →
AI诗歌创作模型对比:Fable、Sol Pro、Kimi K3实测选型指南

AI诗歌创作模型对比:Fable、Sol Pro、Kimi K3实测选型指南

最近AI写诗突然火了起来,但很多开发者发现,不同模型在创意写作上的表现差异巨大。有些模型写出来的诗像是机器拼凑,有些却能写出让人惊艳的句子。到底该选择哪个模型来集成到自己的应用中?今天我们就通过一个实际的对比测试来解答…

2026/7/24 12:48:49阅读更多 →
Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/24 0:58:53阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/24 0:58:53阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/24 0:58:53阅读更多 →
我的编程之路:第一篇博客

我的编程之路:第一篇博客

大家好,我是一名编程初学者,同时这也是我编程学习之路上的第一篇博客。在这里,我想要向大家介绍我的一些想法和规划。a.自我介绍我是一个刚刚接触编程的新手,目前在学习c语言,我对编程世界充满了强烈的好奇。当然&…

2026/7/24 0:00:06阅读更多 →
【LeetCode 54】螺旋矩阵

【LeetCode 54】螺旋矩阵

问题描述: 解法: 1、模拟(参考自【LeetCode 54】螺旋矩阵-CSDN博客) int *spiralOrder(int **matrix, int matrixSize, int *matrixColSize, int *returnSize) {static const int dirs[4][2] {{0, 1}, {1, 0}, {0, -1}, {-1, …

2026/7/24 0:00:06阅读更多 →
2026 WAIC:模型隐身、智能体疯野,厂商竞赛聚焦办公场景与商业闭环

2026 WAIC:模型隐身、智能体疯野,厂商竞赛聚焦办公场景与商业闭环

知春路不相信模型领先今年WAIC大会,昔日AI六小龙来了五家,分别是Kimi、阶跃星辰、Minimax、百川智能、零一万物。连放弃基模的百川和零一万物都来了,唯一缺席的竟是近几个月来风光无限的智谱。(DeepSeek一直不参加)WAI…

2026/7/24 0:00:06阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/23 22:58:43阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/23 18:58:18阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/23 18:58:18阅读更多 →