ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Modern JavaScript Tutorial 的 fetch() 网络请求完全指南:从基础语法到实战应用

Modern JavaScript Tutorial 的 fetch() 网络请求完全指南:从基础语法到实战应用 文档/教程前端【免费下载链接】en.javascript.infoModern JavaScript Tutorial项目地址https://gitcode.com/gh_mirrors/en/en.javascript.info点击查看免费下载fetch()是现代浏览器内置的网络请求 API允许 JavaScript 在不刷新页面的情况下向服务器发送请求、加载新信息。本文以《Modern JavaScript Tutorial》仓库中 5-network/01-fetch/article.md 为骨架结合仓库内的服务端演示代码与配套练习题系统讲解 fetch 的两阶段响应模型、响应体读取方法、请求/响应头操作、POST 请求、二进制数据上传以及并发拉取 GitHub 用户信息的实战模式。读完本文你将掌握用fetch完成从简单 GET 到表单、JSON、图片上传的完整网络通信方案。一、为什么需要 fetchAJAX 与网络请求JavaScript 可以随时向服务器发送网络请求并加载新信息典型场景包括提交订单加载用户信息从服务器接收最新更新……等等。所有这些操作都不需要重新加载页面。这类从 JavaScript 发起网络请求的做法有一个统称AJAXAsynchronousJavaScriptAndXML。虽然名称里带有 XML但如今并不强制使用 XML——这个词来自早期技术时代。你或许已经听说过它。发送网络请求并获取服务器信息的方式有很多种而fetch()是其中现代且功能全面的方法。它不被旧浏览器支持但可以通过 polyfill 补充在主流现代浏览器中支持度非常好。二、fetch 基础语法与两阶段响应模型fetch()的基本语法非常简洁let promise fetch(url, [options])url—— 要访问的 URLoptions—— 可选参数method、headers 等。如果不传options则默认发起一个简单的 GET 请求下载url的内容。浏览器会立即发起请求并返回一个 Promise调用方代码使用它来获取结果。获取响应通常是一个两阶段的过程第一阶段fetch返回的 Promise 在服务器响应头到达时立即 resolve得到一个内置Response类的对象。在这一阶段你可以检查 HTTP 状态码判断请求是否成功、查看响应头但还拿不到响应体。如果fetch无法发起 HTTP 请求例如网络问题、站点不存在Promise 会 reject。注意异常的 HTTP 状态码如 404、500并不会导致 Promise 报错它们只是普通的成功响应。在响应对象上可以查看 HTTP 状态status—— HTTP 状态码例如 200ok—— 布尔值HTTP 状态码为 200-299 时为true。典型写法let response await fetch(url); if (response.ok) { // HTTP-status 为 200-299 // 获取响应体方法见下文 let json await response.json(); } else { alert(HTTP-Error: response.status); }第二阶段读取响应体需要额外的方法调用。Response提供了多个基于 Promise 的方法以不同格式读取响应体response.text()—— 将响应读取为文本response.json()—— 将响应解析为 JSONresponse.formData()—— 将响应作为FormData对象返回详见下一章 FormDataresponse.blob()—— 将响应作为 Blob 返回带类型的二进制数据response.arrayBuffer()—— 将响应作为 ArrayBuffer 返回二进制数据的底层表示另外response.body是一个ReadableStream对象允许你逐块读取响应体后文会给出示例。实战从 GitHub API 拉取 JSON例如获取 GitHub 上最新提交的 JSON 对象let url https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits; let response await fetch(url); let commits await response.json(); // 读取响应体并解析为 JSON alert(commits[0].author.login);同样的逻辑不用await使用纯 Promise 语法fetch(https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits) .then(response response.json()) .then(commits alert(commits[0].author.login));要获取响应文本用await response.text()代替.json()let response await fetch(https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits); let text await response.text(); // 将响应体读取为文本 alert(text.slice(0, 80) ...);实战以 Blob 方式下载并展示二进制内容作为二进制格式读取的展示案例仓库文章演示了下载 fetch 规范关于Blob的操作详见 Blob 章节let response await fetch(/article/fetch/logo-fetch.svg); let blob await response.blob(); // 作为 Blob 对象下载 // 为它创建 img let img document.createElement(img); img.style position:fixed;top:10px;left:10px;width:100px; document.body.append(img); // 展示它 img.src URL.createObjectURL(blob); setTimeout(() { // 三秒后隐藏 img.remove(); URL.revokeObjectURL(img.src); }, 3000);重要限制只能选择一种响应体读取方法注意只能选择一种读取响应体的方法。如果已经通过response.text()获取了响应那么response.json()将无法工作因为响应体内容已被消费。let text await response.text(); // 响应体已被消费 let parsed await response.json(); // 失败已消费三、Response headers读取响应头响应头位于response.headers这是一个类似 Map 的对象。它不完全是 Map但提供了类似的方法可以按名称获取单个头或遍历所有头let response await fetch(https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits); // 获取单个响应头 alert(response.headers.get(Content-Type)); // application/json; charsetutf-8 // 遍历所有响应头 for (let [key, value] of response.headers) { alert(${key} ${value}); }四、Request headers设置请求头与禁止头列表要设置请求头可以在fetch中使用headers选项传入一个包含出站请求头的对象let response fetch(protectedUrl, { headers: { Authentication: secret } });但存在一份**禁止设置的 HTTP 头forbidden HTTP headers**列表浏览器不允许你设置它们Accept-Charset、Accept-EncodingAccess-Control-Request-HeadersAccess-Control-Request-MethodConnectionContent-LengthCookie、Cookie2DateDNTExpectHostKeep-AliveOriginRefererTETrailerTransfer-EncodingUpgradeViaProxy-*Sec-*这些头由浏览器独占控制以确保 HTTP 的正确性与安全性。五、POST 请求提交 JSON 数据要发起POST请求或其他方法需要用到fetch的选项method—— HTTP 方法例如POSTbody—— 请求体可以是以下之一字符串例如 JSON 编码的文本FormData对象以multipart/form-data提交数据Blob/BufferSource用于发送二进制数据URLSearchParams以x-www-form-urlencoded编码提交数据较少使用。绝大多数情况下使用 JSON 格式。例如下面的代码将user对象作为 JSON 提交let user { name: John, surname: Smith }; let response await fetch(/article/fetch/post/user, { method: POST, headers: { Content-Type: application/json;charsetutf-8 }, body: JSON.stringify(user) }); let result await response.json(); alert(result.message);请注意如果请求body是字符串Content-Type头默认会被设置为text/plain;charsetUTF-8。但由于我们要发送 JSON所以通过headers选项显式改为application/json——这才是 JSON 编码数据正确的Content-Type。仓库中的配套服务端实现文章中的/article/fetch/post/user路由对应仓库里的演示服务 5-network/01-fetch/post.view/server.js。它是一个基于 Koa 的小型服务器源码如下const Koa require(koa); const app new Koa(); const bodyParser require(koa-bodyparser); const getRawBody require(raw-body) const Router require(koa-router); let router new Router(); router.post(/user, async (ctx) { ctx.body { message: User saved. }; }); router.post(/image, async (ctx) { let body await getRawBody(ctx.req, { limit: 1mb }); ctx.body { message: Image saved, size:${body.length}. }; }); app .use(bodyParser()) .use(router.routes()) .use(router.allowedMethods()); if (!module.parent) { http.createServer(app.callback()).listen(8080); } else { exports.accept app.callback(); }从源码可以看到POST /user返回{ message: User saved. }POST /image通过raw-body读取原始请求体限制为 1MB返回图片大小。这印证了文章示例中response.json()读到的result.message的来源同时limit: 1mb也提示了上传二进制数据的体量边界。该服务器默认监听 8080 端口同时导出了accept回调供测试环境挂载。六、发送二进制数据用 Blob 上传图片fetch也可以使用Blob或BufferSource对象提交二进制数据。文章中的示例页面上有一个canvas可以通过移动鼠标在上面绘图点击 Submit 按钮把图片发送到服务器body stylemargin:0 canvas idcanvasElem width100 height80 styleborder:1px solid/canvas input typebutton valueSubmit onclicksubmit() script canvasElem.onmousemove function(e) { let ctx canvasElem.getContext(2d); ctx.lineTo(e.clientX, e.clientY); ctx.stroke(); }; async function submit() { let blob await new Promise(resolve canvasElem.toBlob(resolve, image/png)); let response await fetch(/article/fetch/post/image, { method: POST, body: blob }); // 服务器返回确认信息和图片大小 let result await response.json(); alert(result.message); } /script /body请注意这里我们没有手动设置Content-Type头因为Blob对象自带类型这里由toBlob生成image/png。对于Blob对象这个类型会自动成为Content-Type的值。配合上一节的服务端代码POST /image正是用getRawBody读取这个 Blob 的原始字节并返回其大小。不使用async/await时submit()函数可以改写成纯 Promise 形式function submit() { canvasElem.toBlob(function(blob) { fetch(/article/fetch/post/image, { method: POST, body: blob }) .then(response response.json()) .then(result alert(JSON.stringify(result, null, 2))) }, image/png); }七、实战练习并发拉取 GitHub 用户仓库在 5-network/01-fetch/01-fetch-users/task.md 中提供了一个综合练习创建一个异步函数getUsers(names)接收 GitHub 登录名数组从 GitHub 拉取用户信息并返回用户数组。给定USERNAME的 GitHub 用户信息 URL 为https://api.github.com/users/USERNAME。关键要求每个用户发起一次fetch请求请求之间互不等待让数据尽快到达如果某个请求失败或用户不存在在结果数组中返回null。仓库中的参考解法见 5-network/01-fetch/01-fetch-users/solution.md对应源码在 5-network/01-fetch/01-fetch-users/_js.view/solution.jsasync function getUsers(names) { let jobs []; for(let name of names) { let job fetch(https://api.github.com/users/${name}).then( successResponse { if (successResponse.status ! 200) { return null; } else { return successResponse.json(); } }, failResponse { return null; } ); jobs.push(job); } let results await Promise.all(jobs); return results; }这个解法的精妙之处在于.then直接挂在fetch上这样一旦拿到响应就立即开始读取.json()不会等待其他请求。如果改成await Promise.all(names.map(name fetch(...)))再对结果调用.json()就会等待所有 fetch 响应完成才逐一解析。把.json()直接接在每个fetch后面可以保证每个请求独立地、尽早地开始按 JSON 读取数据。配套测试 5-network/01-fetch/01-fetch-users/_js.view/test.js 验证了该行为describe(getUsers, function() { it(gets users from GitHub, async function() { let users await getUsers([iliakan, remy, no.such.users]); assert.equal(users[0].login, iliakan); assert.equal(users[1].login, remy); assert.equal(users[2], null); }); });测试用例同时覆盖了正常用户iliakan、remy与不存在的用户no.such.users应返回null。这也是即使主要使用async/await底层 Promise API 依然有用的典型示例。八、总结一个典型的 fetch 请求由两次await调用组成let response await fetch(url, options); // 响应头到达即 resolve let result await response.json(); // 读取 JSON 响应体或者不用awaitfetch(url, options) .then(response response.json()) .then(result /* 处理结果 */)响应属性response.status—— 响应的 HTTP 状态码response.ok—— 状态码为 200-299 时为trueresponse.headers—— 类似 Map 的 HTTP 响应头对象。读取响应体的方法response.text()—— 将响应作为文本返回response.json()—— 将响应解析为 JSON 对象response.formData()—— 将响应作为FormData对象返回multipart/form-data编码见下一章response.blob()—— 将响应作为 Blob 返回带类型的二进制数据response.arrayBuffer()—— 将响应作为 ArrayBuffer 返回底层二进制数据。目前介绍的 fetch 选项method—— HTTP 方法headers—— 包含请求头的对象并非所有头都允许设置body—— 要发送的数据请求体可以是string、FormData、BufferSource、Blob或UrlSearchParams对象。在后续章节中本文所属的 网络请求目录 还会介绍fetch的更多选项与使用场景例如 FormData 表单提交、下载进度、中断请求、跨源请求 等本文介绍的两阶段模型、headers/body/method选项与 Promise 并发技巧是理解它们的基础。赞分享文档/教程前端【免费下载链接】en.javascript.infoModern JavaScript Tutorial项目地址https://gitcode.com/gh_mirrors/en/en.javascript.info点击查看免费下载相关推荐2025最全Fetch API实战指南从基础到高级网络请求全解析2025最全Fetch API实战指南从基础到高级网络请求全解析 为什么现代前端开发离不开Fetch API 你是否还在为XMLHttpRequest的回调Modern JavaScript Tutorial 精读Fetch 跨域请求与 CORS 全流程解密Modern JavaScript Tutorial 精读Fetch 跨域请求与 CORS 全流程解密 跨域请求Cross Origin Request是文档/教程前端JavaScript 特性速览Modern JavaScript Tutorial 基础语法全面回顾JavaScript 特性速览Modern JavaScript Tutorial 基础语法全面回顾 本篇指南对应 Modern JavaScript Tut文档/教程前端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表