深入理解 Fetch API:现代 Web 请求的全能工具
在现代 Web 开发中,与服务器进行数据交互是几乎每个应用都绕不开的核心环节。过去我们常使用 XMLHttpRequest(XHR),但如今,Fetch API 已成为浏览器原生支持的、更现代、更简洁、更强大的网络请求标准。本文将从基础用法到高级场景,全面解析 Fetch API 的使用技巧,涵盖普通请求、文件上传、文件下载、错误处理、请求中断、进度监控等实用内容。
一、什么是 Fetch API? Fetch API 是一个用于发起网络请求的 Promise-based Web API,由浏览器原生提供,无需引入第三方库。它旨在替代传统的 XMLHttpRequest,提供更清晰、更灵活的接口。
✅ 优点:语法简洁、基于 Promise、支持 async/await、可与 Service Worker 配合实现离线能力。 ⚠️ 注意:Fetch 不会自动处理 HTTP 错误状态码 (如 404、500),需手动判断。
二、基础用法 1. GET 请求(获取数据) 1 2 3 4 5 6 7 8 9 fetch ('https://api.example.com/users' ) .then (response => { if (!response.ok ) { throw new Error (`HTTP error! status: ${response.status} ` ); } return response.json (); }) .then (data => console .log (data)) .catch (error => console .error ('Fetch error:' , error));
使用 async/await 更简洁:
1 2 3 4 5 6 7 8 9 10 async function fetchUsers ( ) { try { const response = await fetch ('https://api.example.com/users' ); if (!response.ok ) throw new Error ('Network response was not ok' ); const users = await response.json (); console .log (users); } catch (error) { console .error ('Failed to fetch:' , error); } }
2. POST 请求(发送 JSON 数据) 1 2 3 4 5 6 7 8 9 10 11 const userData = { name : 'Alice' , email : 'alice@example.com' };fetch ('https://api.example.com/users' , { method : 'POST' , headers : { 'Content-Type' : 'application/json' }, body : JSON .stringify (userData) }) .then (res => res.json ()) .then (data => console .log ('Created:' , data));
三、上传文件(File Upload) 上传文件通常使用 FormData 对象,浏览器会自动设置正确的 Content-Type(含 boundary)。
示例:上传单个文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 <input type ="file" id ="fileInput" /> <button onclick ="uploadFile()" > 上传</button > <script > async function uploadFile ( ) { const fileInput = document .getElementById ('fileInput' ); const file = fileInput.files [0 ]; if (!file) return alert ('请选择文件' ); const formData = new FormData (); formData.append ('file' , file); try { const response = await fetch ('/api/upload' , { method : 'POST' , body : formData }); if (response.ok ) { const result = await response.json (); console .log ('上传成功:' , result); } else { throw new Error ('上传失败' ); } } catch (err) { console .error ('上传出错:' , err); } } </script >
🔔 重要提示:使用 FormData 时,不要 手动设置 Content-Type 请求头,否则会破坏 multipart boundary,导致后端无法解析。
四、下载文件(File Download) Fetch 支持下载任意类型文件(图片、PDF、ZIP 等),通过 .blob() 获取二进制数据,再触发浏览器下载。
示例:下载并保存文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 async function downloadFile (url, filename ) { try { const response = await fetch (url); if (!response.ok ) throw new Error ('下载失败' ); const blob = await response.blob (); const downloadUrl = window .URL .createObjectURL (blob); const link = document .createElement ('a' ); link.href = downloadUrl; link.download = filename; document .body .appendChild (link); link.click (); document .body .removeChild (link); window .URL .revokeObjectURL (downloadUrl); } catch (error) { console .error ('下载出错:' , error); } } downloadFile ('/api/report.pdf' , '月度报告.pdf' );
💡 提示:若需显示下载进度(见下文),需结合 ReadableStream 或改用 XHR。
五、高级用法与注意事项 1. 错误处理 Fetch 仅在网络故障时 reject Promise ,HTTP 错误(如 404、500)仍会 resolve。因此必须检查 response.ok 或 response.status。
1 2 3 4 5 6 7 8 9 fetch ('/api/data' ) .then (res => { if (res.status === 401 ) { } else if (!res.ok ) { throw new Error (`Server error: ${res.status} ` ); } return res.json (); });
2. 设置请求头与凭据 1 2 3 4 5 6 7 fetch ('/api/profile' , { headers : { 'Authorization' : 'Bearer ' + token, 'X-Custom-Header' : 'value' }, credentials : 'include' });
3. 中断请求(AbortController) 1 2 3 4 5 6 7 8 9 10 11 12 13 const controller = new AbortController ();const signal = controller.signal ;fetch ('/api/long-task' , { signal }) .then (res => res.json ()) .catch (err => { if (err.name === 'AbortError' ) { console .log ('请求已取消' ); } }); setTimeout (() => controller.abort (), 5000 );
4. 超时控制(结合 AbortController) 1 2 3 4 5 6 function fetchWithTimeout (url, options = {}, timeout = 5000 ) { const controller = new AbortController (); const timeoutId = setTimeout (() => controller.abort (), timeout); return fetch (url, { ...options, signal : controller.signal }) .finally (() => clearTimeout (timeoutId)); }
六、Fetch 的局限性 尽管 Fetch 功能强大,但仍有一些不足:
功能
Fetch 支持情况
替代方案
上传/下载进度
❌(无原生支持)
使用 XHR 或第三方库(如 axios)
自动重试
❌
自行封装或使用库
请求拦截
❌
需手动封装或使用 axios
浏览器兼容性
✅(现代浏览器)
IE 不支持,需 polyfill
📌 对于需要进度条、拦截器等高级功能的项目,axios 仍是更便捷的选择。但对于轻量级、标准化的现代应用,Fetch 完全够用。
七、总结 Fetch API 作为现代 Web 的标准网络接口,具备简洁、强大、原生等优势。掌握其核心用法——包括基础请求、文件上传下载、错误处理、请求中断等——是每个前端开发者的基本功。
✅ 推荐实践:
用 Fetch 替代简单的 XHR 请求;
文件上传用 FormData;
下载文件用 blob() + <a download>;
始终检查 response.ok;
复杂场景可封装成 request 工具函数。
随着 Web 标准的演进,Fetch 正在不断扩展能力(如 fetch() 的流式响应处理),未来将更加强大。拥抱原生,从掌握 Fetch 开始!
参考资料 :