ARTICLE DETAIL

资讯详情

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

JavaScript 调用第三方 API 实战:基于 Fetch 与 Promise 的异步数据获取指南(curriculum 开源课程深度解析)

JavaScript 调用第三方 API 实战:基于 Fetch 与 Promise 的异步数据获取指南(curriculum 开源课程深度解析) JavaScript 调用第三方 API 实战基于 Fetch 与 Promise 的异步数据获取指南curriculum 开源课程深度解析【免费下载链接】curriculumThe open curriculum for learning web development项目地址: https://gitcode.com/GitHub_Trending/cu/curriculum本文以 open curriculumcu/curriculumJavaScript 路径中的 working_with_apis.md 为核心骨架完整讲解 Web 前端调用第三方 API 的完整链路从 API 与 API Key 的基本概念、Visual Crossing 天气 API 的首次请求到用原生fetch替代 XMLHttpRequest、逐层解析 Giphy 的嵌套 JSON 响应再到用async/await重构 Promise 代码最后讨论前端密钥暴露风险与服务端环境变量方案。学完本篇你将能够独立完成注册 API → 构造请求 URL → 前端拉取数据 → 提取并渲染数据 → 处理错误的完整实战流程并具备开发天气应用、GIF 搜索等真实小项目的能力。课程背景这一课在整个 JavaScript 学习路径中的位置该文档位于仓库的 javascript/asynchronous_javascript_and_apis 目录是异步 JavaScript 与 API课程的核心一课前后分别衔接 asynchronous_code.md回调与 Promise 基础与 async_and_await.mdasync/await 语法并以 project_weather_app.md天气应用项目作为落地练习。课程概述明确列出了本篇要解决的四个核心问题解释什么是 API。从宏观上解释如何访问一个 API。解释如何从 API 获取并提取数据。解释为什么你的 API 请求可能被浏览器拦截以及如何修复。什么是 API服务器对外开放数据的窗口APIApplication Programming Interface应用程序编程接口是服务器为外部使用网站或应用提供功能和数据而设计的一套访问接口。为特定网站而建的服务器可以存放博客文章、用户数据、游戏高分等任何内容也有服务器作为开放服务向任何想使用的人提供数据例如天气数据或股票价格。无论是哪种情况访问和使用这些数据的方法本质上是一致的。API 通常通过 URL 被访问而具体如何查询这些 URL取决于你使用的特定服务。例如Visual Crossing 的天气 API 提供了多种可请求的数据类型。要获取某个地点的当前天气可以把城市名直接放入 URL 的路径中https://weather.visualcrossing.com/VisualCrossingWebServices/rest/services/timeline/london把上述 URL 中的london换成你喜欢的城市并粘贴到浏览器地址栏你很可能会收到这样一个错误No API key or session found. Please verify that your API key parameter is correct.这个错误引出了 API 使用中最重要的机制之一——API KeyAPI 密钥。API Key访问权限、配额与计费在大多数情况下你必须在 API 服务商处创建账号并申请一个 API Key才能从它们的端点endpoint即 API 内用于访问特定功能或数据的专用 URL获取数据。拿到 Key 之后通常每次数据请求都要携带它。在 Visual Crossing 中API Key 以查询字符串参数的形式传入https://weather.visualcrossing.com/VisualCrossingWebServices/rest/services/timeline/london?key11111111111111111API Key 的三大作用身份标识与用量追踪API Key 是随机且唯一属于你的。像 Visual Crossing 这样的服务商可以把你的 Key 与你的数据请求包括请求数量和频率关联起来用于统计每个用户的用量。滥用防护签发 API Key 让服务商能够更好地追踪对其系统和数据的滥用行为。成本回收与商业变现服务商可以通过不同档位的付费套餐来回收运行服务器的成本。以 Visual Crossing 为例免费版允许每天 1000 次调用但提供的信息有限对个人小项目来说通常足够而 Enterprise 版本提供每月无限次 API 调用并额外提供 Energy 数据、Maritime 数据等高级功能。一次 API 请求的成本或许只有几厘钱但如果你用它做出了一个全球流行的天气应用每分钟可能有成千上万人访问数据流量成本会迅速膨胀——这就是大多数 API 服务商都提供付费档位的原因付费可以换取更高频的请求配额或更多数据访问权限。顺带一提Visual Crossing 官方提供**查询构建器query builder**工具你可以只输入区域来构建查询并在 API 标签页中看到实际生成的查询 URL 结构——这是学习如何构造 API 查询的绝佳辅助工具。第一次成功请求前往 Visual Crossing 注册一个免费账号即可获得 API Key可在账号资料页找到。把 Key 作为查询字符串参数拼入 URL 后你应该会收到一个正常的响应类似下面这样实际响应比这个示例长得多{queryCost:1,latitude:51.5064,longitude:-0.12721,resolvedAddress:London, England, United Kingdom,address:london,timezone:Europe/London,tzoffset:1.0,description:Similar temperatures continuing with a chance of rain tomorrow, Tuesday Thursday.,days:[{datetime:2024-07-06,datetimeEpoch:1720220400,tempmax:61.4,tempmin:53.1,temp:57.8,feelslikemax:61.4,feelslikemin:53.1,feelslike:57.8,dew:51.3,humidity:79.7,precip:0.457,precipprob:100.0,precipcover:75.0,preciptype:[rain],snow:0.0,snowdepth:0.0,windgust:35.3,windspeed:21.9,winddir:262.6,pressure:1001.8,cloudcover:70.5,visibility:8.3,solarradiation:147.5,solarenergy:12.9,uvindex:6.0,severerisk:10.0,sunrise:04:52:02,sunriseEpoch:1720237922,sunset:21:18:20,sunsetEpoch:1720297100,moonphase:0.02,conditions:Rain, Partially cloudy,description:Partly cloudy throughout the day with a chance of rain throughout the day.,icon:rain,stations:[EGWU,EGLL,D5621,EGLC]}]}响应中的days数组包含逐日天气明细最高/最低温、体感温度、湿度、降水概率、日出日落时间、天气图标等这正是后续天气应用项目的数据基础。前置知识回调与 Promise在正式动手之前需要先理解异步编程的两个基础概念它们在本篇及 asynchronous_code.md 中有详细展开回调函数Callback作为参数传入另一个函数、并在外层函数内部被调用的函数。例如addEventListener(click, function(){ ... })。回调在简单场景很好用但一旦需要按顺序链式串联多个异步操作就会陷入难以维护的回调地狱callback hell。Promise一个可能在未来某个时刻产生值的对象。核心价值在于解决数据还没取回来代码就继续往下执行的问题asynchronous_code.md。如果getData()返回一个 Promise你可以这样等待结果const myData getData(); // 如果被重构为返回一个 Promise... myData.then(function(data) { // .then() 告诉它等待 Promise 被 resolve const pieceOfData data[whatever]; // 然后再执行内部函数 });.then()的作用是等 Promise 成功 resolve 后再运行传入的函数.catch()则用于捕获拒绝rejected的 Promise。理解了这两个方法下面的fetch代码就顺理成章了。浏览器请求 API 的演进从 XHR 到 fetch痛苦的过去XMLHttpRequest几年前在代码中访问 API 数据的主要方式还是XMLHttpRequest。这个函数至今仍在所有浏览器中可用但用起来非常不友好// 光是获取 XHR 就是一团糟 if (window.XMLHttpRequest) { // Mozilla, Safari, ... request new XMLHttpRequest(); } else if (window.ActiveXObject) { // IE try { request new ActiveXObject(Msxml2.XMLHTTP); } catch (e) { try { request new ActiveXObject(Microsoft.XMLHTTP); } catch (e) {} } } // Open, send. request.open(GET, https://url.com/some/url, true); request.send(null);这段代码既冗长又要处理不同浏览器的历史分支体验极差。于是开发者开始编写第三方库来简化请求比较流行的有 axios 和 superagent它们各有优缺点。然而浏览器后来实现了原生的 HTTP 请求函数——fetch这也是本课程选定并推荐的方式。现在原生 fetch// URL必填options可选 fetch(https://url.com/some/url) .then(function(response) { // 请求成功 :) }) .catch(function(err) { // 请求出错 :( });对比上面的 XHR 代码fetch 的写法干净得多。注意其中的.then()和.catch()——这正是前面提到的Promisefetch 本身返回一个 Promise因此可以直接链式调用这两个方法。实战用 Giphy API 在页面展示随机 GIF下面我们切换 API用一个真实可运行的例子把整个流程串起来调用 Giphy API在网页上展示一张随机 GIF。Giphy 提供多种搜索和查找 GIF 的方法这里使用最简单的translate端点。其正确 URL 是api.giphy.com/v1/gifs/translate需要两个必填参数api_key你的 Giphy API Key需注册 Giphy 开发者账号并免费申请s搜索词search term。此外还有可选参数例如rating可以按内容敏感度过滤结果。把参数拼好使用你自己的 Key应该得到类似这样的 URLhttps://api.giphy.com/v1/gifs/translate?api_keyYOUR_KEY_HEREscatsratingg // 当然是搜索猫啦在浏览器中打开这个 URL替换成你的 Key一切顺利的话会返回一长串 JSON 数据。搭建页面骨架为了专注核心逻辑我们把所有代码放在单个 HTML 文件中在body里放一个空白的img标签和一个空的script标签。!DOCTYPE html html langen head meta charsetUTF-8 titleDocument/title /head body img src# script /script /body /html第一步选中图片元素在 script 中先选中图片元素并赋值给变量以便收到数据后替换它的 URLscript const img document.querySelector(img); /script第二步发起 fetch 请求加上前面构造好的 Giphy URLscript const img document.querySelector(img); fetch(https://api.giphy.com/v1/gifs/translate?api_keyYOUR_KEY_HEREscatsratingg) .then(function(response) { console.log(response.json()); }); /script打开 HTML 文件页面上什么都看不到但控制台里会有一行输出。整个流程中最容易卡住的地方就在这里response.json()返回的是另一个 Promise也就是说要把响应体解析为 JavaScript 对象还需要再链一个.then()。第三步解析 JSON 需要二次 .then()script const img document.querySelector(img); fetch(https://api.giphy.com/v1/gifs/translate?api_keyYOUR_KEY_HEREscatsratingg) .then(function(response) { return response.json(); }) .then(function(response) { console.log(response); }); /script现在你得到了一个真正的 JavaScript 对象。仔细观察会发现我们需要的图片 URL 被嵌套在对象相当深的位置。第四步逐层穿透嵌套数据从上面的控制台截图可以看到Giphy 的响应结构大致为根对象 →data→images→ 具体尺寸如original→url。要拿到图片地址必须逐层深入script const img document.querySelector(img); fetch(https://api.giphy.com/v1/gifs/translate?api_keyYOUR_KEY_HEREscatsratingg) .then(function(response) { return response.json(); }) .then(function(response) { console.log(response.data.images.original.url); }); /script第五步把 URL 赋给图片元素运行文件控制台会打印出图片的 URL。最后一步把页面上img的src设为这个地址script const img document.querySelector(img); fetch(https://api.giphy.com/v1/gifs/translate?api_keyYOUR_KEY_HEREscatsratingg) .then(function(response) { return response.json(); }) .then(function(response) { img.src response.data.images.original.url; }); /script一切顺利的话每次刷新页面都会出现一张新的 GIF 图片——因为你每刷新一次就向 Giphy 的 translate 端点发起了一次随机查询。至此你已经完成了注册 → 构造 URL → fetch → 解析 JSON → 提取嵌套数据 → 渲染到页面的完整闭环。深入用 async/await 重构 Promise 链Promise 链写起来清晰但一旦逻辑变多链式结构依然不够直观。JavaScript 提供了async/await两个关键字让异步代码读起来更像同步代码同时保留异步的优势。async_and_await.md 给出了两个行为完全等价的函数示例一个是.then()链另一个是async/await写法async_and_await.md。关键知识点async_and_await.mdasync关键字告诉 JavaScript 引擎你在声明一个异步函数是函数内使用await的前提。用async声明的函数自动返回一个 Promise——在 async 函数中return等价于 resolve抛出的错误等价于 reject。本质上async 函数就是 Promise 的语法糖。await关键字告诉 JavaScript 等待一个异步动作完成后再继续执行该函数相当于暂停直到完成。它用于在原本要写.then()的地方取出值不再链式调用.then()而是把结果直接赋给一个变量。下面把前面的 Giphy 代码逐步改造成 async/await 风格。由于await不能在非模块脚本的顶层使用需要先创建一个 async 函数包裹 API 调用。第 1 步把 fetch 链包进 async 函数此时内部仍是 Promise 链script const img document.querySelector(img); async function getCats() { fetch(https://api.giphy.com/v1/gifs/translate?api_keyYOUR_KEY_HEREscats) .then(function(response) { return response.json(); }) .then(function(response) { img.src response.data.images.original.url; }) .catch(function(error) { console.error(error); }); } /script第 2 步对 fetch 使用 awaitresponse仍是之前传给.then()的那个对象仍需调用.json()而.json()又返回 Promisescript const img document.querySelector(img); async function getCats() { const response await fetch(https://api.giphy.com/v1/gifs/translate?api_keyYOUR_KEY_HEREscats); response.json().then(function(response) { img.src response.data.images.original.url; }).catch(function(error) { console.error(error); }); } /script第 3 步对.json()也使用 await——因为.json()返回 Promise可以用await把解析结果直接赋给变量script const img document.querySelector(img); async function getCats() { const response await fetch(https://api.giphy.com/v1/gifs/translate?api_keyYOUR_KEY_HEREscats); const catData await response.json(); img.src catData.data.images.original.url; } /script第 4 步用 try...catch 处理错误——不再链式调用.catch()而是把正常代码放进try块、错误处理放进catch块async_and_await.mdscript const img document.querySelector(img); async function getCats() { try { const response await fetch(https://api.giphy.com/v1/gifs/translate?api_keyYOUR_KEY_HEREscats); const catData await response.json(); img.src catData.data.images.original.url; } catch (error) { console.error(error); } } getCats(); /script这段代码与上一课基于 Promise 的版本行为完全一致只是写法更接近同步代码。请始终记住async/await 只是 Promise 的另一种写法二者可以随时互相转换。错误处理的陷阱fetch 对非 2XX 状态不抛错一个非常容易踩坑的细节是只要 API 有响应哪怕返回404 Not Found或其他非 2XX 状态码对 fetch 来说都是一次有效响应因此.catch()不会执行。.catch()只会在以下情况触发网络层面失败或者你后续的 JavaScript 代码抛出了错误例如访问undefined的属性或者你手动throw了错误。所以如果想针对API 没有给出期望响应例如 404做条件处理必须在.then()里手动检查。可以借助 Response 对象上的有用属性如response.ok、response.status来实现fetch(https://api.giphy.com/v1/gifs/translate?api_keyYOUR_KEY_HEREscats) .then(function(response) { if (!response.ok) { throw new Error(HTTP error! status: ${response.status}); } return response.json(); }) .then(function(data) { img.src data.data.images.original.url; }) .catch(function(error) { console.error(error); // 现在 404 等错误也会走到这里 });课后练习与实战项目本课作业查看公开 API 列表放飞想象力选择一个感兴趣的 API 练手。扩展上面的小项目添加一个按钮点击即可获取新图片而无需刷新页面。添加一个搜索框让用户可以搜索特定的 GIF。为无效 URL 等场景添加.catch()错误处理务必结合上文非 2XX 不抛错的机制必要时在.then()中手动抛出错误。综合应用天气应用项目课程在 project_weather_app.md 中提供了一个完整的综合练习使用前面学过的 Visual Crossing API 构建一个天气预测网站要求能够搜索具体地点、并在华氏度与摄氏度之间切换显示。项目还建议根据数据改变页面外观如改变背景色或用 Giphy API 展示与天气相关的 GIFPromise 和 async/await 两种风格都尝试使用编写命中 API 的函数接收地点并返回天气数据与处理 JSON 数据的函数只提取应用所需字段并返回新对象分层设计用表单接收用户输入的地点并触发请求可选用 DevTools 模拟网络速度添加一个加载中组件。这个项目把本课的全部知识点URL 构造、API Key、fetch、JSON 解析、数据提取、错误处理整合成一个真实可部署的小应用是检验掌握程度的试金石。API Key 安全为什么不能把密钥写进前端本课在演示时把 API Key 直接放进了 URL但这只适用于免费 Key。原因很现实密钥会暴露在客户端放在前端浏览器里的 Key 被视为公开信息。GitHub 上爬取硬编码 API Key 的机器人非常多恶意者拿到后就能盗用你已经付费的服务和数据——历史上甚至发生过有人因把 AWS 密钥提交到 GitHub 而蒙受巨额损失的著名事故。请求会被限流与盗刷API 可能按次计费或被限流密钥一旦泄露别人可以耗尽你的全部配额。嗅探风险Key 直接写在 URL 中网络流量嗅探者甚至你身后偷看屏幕的人都能轻易获取它。正确做法把密钥留在服务端课程给出的正确方向是将 API Key 存储在服务器上通过环境变量提供给应用绝不发送到前端。这一点在 NodeJS 路径的 environment_variables.md 中有系统讲解环境变量是与环境相关、随环境变化的变量非常适合存储数据库 URL、凭据、API Key 等机密environment_variables.md可以在项目根目录创建.env文件按NAMEVALUE格式存放密钥并把.env加入.gitignore防止提交到公开仓库environment_variables.md在代码中通过 Node 内置的process.env对象读取例如process.env.WEATHER_API_KEYenvironment_variables.md。这也是课程反复强调永远不要信任客户端的原因——不仅不能信任来自客户端的数据也不能信任发送给客户端的任何内容包括 API Key。GitHub 检测到公开仓库中提交了 API Key 时会发出安全警报这正是为了提醒你这一风险。不过在目前的前端阶段这一安全话题大多可以先放一放本课程使用的是免费 API 访问应用也主要供自己和看作品集的人使用。服务端密钥管理会在 Full Stack JavaScript 路径的后端课程中详细覆盖在 Ruby 课程中如果你还没学到后面也会讲到。知识自检什么是 API——服务器对外提供数据和功能的接口通常通过 URL 访问。如何限制对 API 的访问——通过 API Key注册账号获取密钥每次请求携带密钥服务商据此追踪用量、防滥用并计费。如何从 API 获取并提取数据——用fetch发起请求.then(response response.json())解析 JSON或使用async/await的const data await response.json()再通过属性访问逐层提取嵌套数据。延伸阅读本文核心内容出自 working_with_apis.md前置概念详见 asynchronous_code.mdasync/await 重构详见 async_and_await.md综合练习见 project_weather_app.md服务端密钥管理可继续学习 environment_variables.md。【免费下载链接】curriculumThe open curriculum for learning web development项目地址: https://gitcode.com/GitHub_Trending/cu/curriculum创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表