介绍
在本实验中,你将学习使用现代 JavaScript 与 Web API 进行交互的关键技能。你将探索 fetch API,这是一个内置于浏览器中强大而灵活的工具,用于发出异步网络请求。主要目标是理解如何从服务器请求数据、处理响应以及管理潜在的错误,从而为你构建动态 Web 应用打下基础。
你将从发出一个基本的 GET 请求来检索数据开始,然后学习如何处理响应、将其解析为 JSON,并将获取到的数据显示在 HTML 元素中。本实验还涵盖了关键方面,例如实现健壮的错误处理、发出 POST 请求将数据发送到服务器,以及使用 API 密钥对请求进行身份验证。
使用 fetch API 发起基础 GET 请求
在本步骤中,你将学习如何在 JavaScript 中进行一次基础的 API 调用:GET 请求。我们将使用 fetch API,这是一个现代、强大且灵活的工具,内置于所有现代 Web 浏览器中,并且在 Node.js 18+ 环境中也可用。它允许我们异步地从服务器请求资源。
fetch 函数是基于 Promise 的,这意味着它返回一个 Promise,该 Promise 会解析为请求的 Response,无论请求成功与否。这使得我们可以在异步操作完成后处理其结果。
首先,让我们创建一个文件来编写代码。在屏幕左侧的文件浏览器中,在 ~/project 目录下创建一个名为 index.js 的新文件。
我们将在此示例中使用 JSONPlaceholder API。它是一个免费的、虚假的在线 REST API,非常适合用于测试和原型设计。我们将请求一个单独的“todo”项。
现在,将以下代码添加到你的 index.js 文件中。这段代码定义了 API 端点 URL,并使用 fetch 发起一个 GET 请求。
// 定义单个 todo 项的 API URL
const apiUrl = "https://jsonplaceholder.typicode.com/todos/1";
// 使用 fetch API 发起 GET 请求
fetch(apiUrl)
.then((response) => {
// fetch 函数返回一个 Promise。
// 第一个 .then() 块接收 Response 对象。
// 我们需要调用 response 上的 .json() 方法将响应体文本解析为 JSON。
return response.json();
})
.then((data) => {
// 第二个 .then() 块接收解析后的 JSON 数据。
console.log("Data fetched successfully:");
console.log(data);
})
.catch((error) => {
// 如果在 fetch 操作期间发生任何错误,.catch() 块将被执行。
console.error("Error fetching data:", error);
});
让我们分解一下这段代码:
apiUrl: 我们将要访问的 API 端点的 URL 存储在一个常量中。fetch(apiUrl): 这会向指定的 URL 发起 GET 请求并返回一个Promise。.then(response => response.json()): 当Promise解析时,会调用此函数。response对象不是实际的 JSON 数据,而是整个 HTTP 响应的表示。我们调用response.json()方法来提取 API 的 JSON 响应体内容,该方法本身会返回另一个Promise。.then(data => { ... }): 第二个.then()处理由response.json()返回的Promise。data参数现在包含了来自 API 的实际 JSON 对象。我们将此数据记录到控制台。.catch(error => { ... }): 如果Promise在任何时候被拒绝(例如,由于网络错误),此块将捕获错误并将其记录到控制台。
要执行你的脚本并查看结果,请在 WebIDE 中打开一个新的终端,然后运行以下命令:
node ~/project/index.js
你应该会在控制台中看到获取到的数据被打印出来,这代表了来自 API 的一个单独的“todo”项。
预期输出:
Data fetched successfully:
{ userId: 1, id: 1, title: 'delectus aut autem', completed: false }

处理响应并解析 JSON 数据
在本步骤中,我们将更深入地探讨如何处理 API 调用的响应。当你使用 fetch 时,服务器会返回一个 Response 对象。我们将了解这个对象包含什么,以及如何从其响应体中正确解析 JSON 数据以在你的应用程序中使用。
你在第一个 .then() 块中收到的 Response 对象本身并不是数据。它是整个 HTTP 响应的表示,包括状态码(如 200 表示成功)、头部信息和响应体。响应体是数据流,要使用它,你需要读取它。
fetch API 提供了几种读取响应体的方法,例如用于纯文本的 .text() 和用于解析 JSON 数据的 .json()。.json() 方法会读取响应流直到完成,并返回一个新的 Promise,该 Promise 会解析为将响应体文本解析为 JavaScript 对象的结果。这就是为什么我们需要链式调用第二个 .then() 来处理实际数据。
让我们修改 ~/project/index.js 文件来演示这一点。我们不再仅仅记录整个数据对象,而是会访问并记录其中的特定属性,以表明我们拥有一个可以操作的常规 JavaScript 对象。
使用以下代码更新你的 ~/project/index.js 文件内容:
// 定义单个 todo 项的 API URL
const apiUrl = "https://jsonplaceholder.typicode.com/todos/1";
fetch(apiUrl)
.then((response) => {
// response.json() 方法解析响应的 JSON 主体
// 并返回一个解析为结果 JavaScript 对象的 Promise。
return response.json();
})
.then((data) => {
// 现在 'data' 是一个 JavaScript 对象。我们可以访问它的属性。
console.log("Successfully parsed JSON data:");
console.log(`Todo Title: ${data.title}`);
console.log(`Is Completed: ${data.completed}`);
})
.catch((error) => {
// 如果在 fetch 操作期间发生任何错误,.catch() 块将被执行。
console.error("Error fetching or parsing data:", error);
});
在这段更新的代码中,第二个 .then() 块现在将 data 作为 JavaScript 对象接收。我们使用模板字面量(反引号 ` 语法)来创建包含 data.title 和 data.completed 值的字符串,这表明 JSON 已成功解析。
现在,在终端中再次执行脚本,查看新的输出:
node ~/project/index.js
你将看到一个更结构化的输出,确认你已成功访问了已解析 JSON 对象的属性。
预期输出:
Successfully parsed JSON data:
Todo Title: delectus aut autem
Is Completed: false
在 HTML 元素中显示获取的数据
在本步骤中,你将学习如何将从 API 获取的数据显示在网页上。虽然将数据记录到控制台对于开发很有用,但最终目标通常是将此信息呈现给用户。这需要一个 HTML 文件来构建内容结构,以及 JavaScript 来操作文档对象模型 (DOM)。
首先,我们需要一个 HTML 文件。在左侧的文件浏览器中,在 ~/project 目录下创建一个名为 index.html 的新文件。
将以下基本 HTML 结构添加到你的 index.html 文件中。此文件包含一个标题和一个 ID 为 data-output 的 div 元素,它将作为我们获取数据的容器。正文末尾的 <script> 标签确保我们的 JavaScript 在 HTML 元素加载后运行。
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>API Data Display</title>
</head>
<body>
<h1>Fetched Todo Item</h1>
<div id="data-output">
<p>Loading data...</p>
</div>
<script src="index.js"></script>
</body>
</html>
接下来,你需要修改你的 ~/project/index.js 文件以与此 HTML 进行交互。脚本将不再记录到控制台,而是通过 ID 查找 div 元素,并用 API 中的数据更新其内容。
用以下代码替换 ~/project/index.js 的内容:
const apiUrl = "https://jsonplaceholder.typicode.com/todos/1";
// 选择我们将显示数据的 HTML 元素
const outputElement = document.getElementById("data-output");
fetch(apiUrl)
.then((response) => response.json())
.then((data) => {
// 获取到数据后,我们更新 HTML 内容。
// 我们使用 innerHTML 将“Loading...”消息替换为结构化数据。
outputElement.innerHTML = `
<p><strong>Title:</strong> ${data.title}</p>
<p><strong>Completed:</strong> ${data.completed}</p>
`;
})
.catch((error) => {
// 如果发生错误,向用户显示错误消息。
outputElement.textContent = "Failed to load data.";
console.error("Error fetching data:", error);
});
现在,要查看结果,你需要通过 Web 服务器来提供这些文件。LabEx 环境包含 Python,它有一个简单的内置 Web 服务器。
- 在 WebIDE 中打开一个新的终端。
- 通过运行以下命令启动 Web 服务器。这将从当前目录 (
~/project) 在端口 8080 上提供文件。
python3 -m http.server 8080
- LabEx 平台将检测到此正在运行的服务,并提供一个“Web 8080”选项卡来预览你的
index.html页面。

你现在应该看到你的网页显示了获取到的“todo”项的标题和完成状态,取代了最初的“Loading data...”消息。
为 API 调用实现错误处理
在本步骤中,我们将通过实现适当的错误处理来增强 API 调用的健壮性。API 请求可能因各种原因而失败,例如错误的 URL、网络问题或服务器端问题。妥善处理这些潜在的故障对于提供更好的用户体验至关重要。
fetch API 的一个关键细节是,它的 Promise 不会在 HTTP 错误状态(如 404 Not Found 或 500 Internal Server Error)下被拒绝。只有在发生阻止请求完成的网络故障时,它才会拒绝。为了处理 HTTP 错误,我们需要检查 response.ok 属性,对于成功响应(状态码 200-299),该属性为 true。
让我们更新我们的 ~/project/index.js 来检查响应状态并处理潜在的错误。
用以下代码替换你的 ~/project/index.js 文件内容。我们在第一个 .then() 块中添加了一个检查。
const apiUrl = "https://jsonplaceholder.typicode.com/todos/1";
const outputElement = document.getElementById("data-output");
fetch(apiUrl)
.then((response) => {
// 检查响应是否成功。
// 'ok' 属性是一个布尔值,如果状态码在 200-299 范围内则为 true。
if (!response.ok) {
// 如果不成功,我们抛出一个错误,该错误将被 .catch() 块捕获。
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.then((data) => {
outputElement.innerHTML = `
<p><strong>Title:</strong> ${data.title}</p>
<p><strong>Completed:</strong> ${data.completed}</p>
`;
})
.catch((error) => {
// 在 HTML 元素中显示用户友好的错误消息。
outputElement.textContent = "Failed to load data. Please try again later.";
// 为了调试目的,将技术错误记录到控制台。
console.error("Error fetching data:", error);
});
为了实际看到我们的错误处理效果,让我们故意使用一个无效的 API URL。修改 ~/project/index.js 中的 apiUrl 指向一个不存在的资源。这将导致 API 返回一个 404 Not Found 错误。
在你的 index.js 文件中更改此行:
const apiUrl = 'https://jsonplaceholder.typicode.com/todos/1';
为:
const apiUrl = 'https://jsonplaceholder.typicode.com/invalid-path/1';
现在,让我们看看结果。如果上一步中的 Python Web 服务器仍在运行,只需刷新浏览器中的预览选项卡。如果已停止,请从终端重新启动它:
python3 -m http.server 8080
然后,打开预览。你将在页面上看到错误消息,而不是数据,因为我们的 if (!response.ok) 检查捕获了 404 错误。
网页上的预期输出:
Failed to load data. Please try again later.
重要提示: 在进行下一步之前,请记住将 apiUrl 改回正确的 URL:https://jsonplaceholder.typicode.com/todos/1。
发送 POST 请求以发送数据
在本步骤中,你将学习如何使用 POST 请求将数据发送到服务器。到目前为止,我们只获取(或“GET”)了数据。POST 请求用于向指定资源提交数据,通常会导致服务器上的状态更改或创建新条目。
为此,我们需要向 fetch 函数提供更多信息,包括请求方法、描述我们发送数据的标头以及请求体中的数据本身。
首先,让我们更新 ~/project/index.html 文件以包含一个表单。这将允许我们输入数据,然后将其发送到 API。用以下内容替换 index.html 的全部内容:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>POST Request Example</title>
</head>
<body>
<h1>Create a New Todo Item</h1>
<form id="add-todo-form">
<input
type="text"
id="todo-title"
placeholder="Enter a new todo title"
required
/>
<button type="submit">Add Todo</button>
</form>
<hr />
<h2>Server Response:</h2>
<div id="response-output"></div>
<script src="index.js"></script>
</body>
</html>
此 HTML 创建了一个简单的表单,其中包含一个文本输入框和一个提交按钮,以及一个用于显示服务器响应的 div。
接下来,我们将完全替换 ~/project/index.js 中的代码,以处理表单提交并执行 POST 请求。
用以下代码替换 ~/project/index.js 的内容:
// 用于创建新待办事项的 API 端点
const apiUrl = "https://jsonplaceholder.typicode.com/todos";
// 从 DOM 获取表单和响应输出元素
const todoForm = document.getElementById("add-todo-form");
const responseOutput = document.getElementById("response-output");
// 为表单的 submit 事件添加事件监听器
todoForm.addEventListener("submit", function (event) {
// 阻止表单的默认提交行为
event.preventDefault();
// 从输入字段获取标题
const todoTitle = document.getElementById("todo-title").value;
// 我们想在 POST 请求中发送的数据
const newTodo = {
title: todoTitle,
completed: false,
userId: 1
};
// fetch 请求的选项
const requestOptions = {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(newTodo)
};
// 执行 POST 请求
fetch(apiUrl, requestOptions)
.then((response) => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
// API 会返回创建的对象,包括一个新的 'id'
return response.json();
})
.then((data) => {
// 在我们的输出 div 中显示服务器的响应
responseOutput.innerHTML = `<p>Successfully created todo!</p><pre>${JSON.stringify(data, null, 2)}</pre>`;
})
.catch((error) => {
responseOutput.textContent = "Failed to create todo.";
console.error("Error:", error);
});
});
让我们分解一下新的 requestOptions 对象:
method: 'POST': 这告诉fetch执行一个 POST 请求。headers: { 'Content-Type': 'application/json' }: 此标头通知服务器体中的数据是 JSON 格式。body: JSON.stringify(newTodo): 这是我们要发送的实际数据。在发送之前必须将其转换为 JSON 字符串。
现在,如果你的 Web 服务器尚未运行,请再次启动它:
python3 -m http.server 8080
打开预览,在输入字段中输入新待办事项的标题,然后单击“Add Todo”按钮。你应该会看到一条成功消息以及服务器返回的数据,其中包括你“创建”的条目的新 id。

使用 API 密钥进行身份验证
在本步骤中,你将学习如何使用 API 密钥对 API 请求进行认证。许多 API 都需要认证来识别用户、控制数据访问和跟踪使用情况。API 密钥是你随请求一起包含的唯一字符字符串,用于证明你拥有使用 API 的权限。
发送 API 密钥有几种方法,但一种常见且安全的方法是将其包含在请求标头中,通常使用 Authorization 标头。
在本示例中,我们将模拟获取需要 API 密钥的受保护用户数据。我们将修改代码以包含一个带有“Bearer”令牌的 Authorization 标头,这是一种发送认证凭据的标准方法。
首先,让我们简化 ~/project/index.html 文件,使其仅显示获取的用户数据。用以下内容替换其内容:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Authenticated API Request</title>
</head>
<body>
<h1>User Profile (Protected)</h1>
<div id="user-profile">
<p>Loading user data...</p>
</div>
<script src="index.js"></script>
</body>
</html>
接下来,用下面的代码替换 ~/project/index.js 的内容。此脚本将执行 GET 请求来获取用户数据,并在标头中包含一个假的 API 密钥。
// 定义用户配置文件的 API URL
const apiUrl = "https://jsonplaceholder.typicode.com/users/1";
// 在实际应用中,你会从你的 API 提供商那里获取这个密钥。
const apiKey = "YOUR_SECRET_API_KEY_HERE";
// 选择用于输出的 HTML 元素
const userProfileElement = document.getElementById("user-profile");
// 创建请求选项对象,包括用于认证的标头
const requestOptions = {
method: "GET",
headers: {
Authorization: `Bearer ${apiKey}`
}
};
// 执行已认证的 GET 请求
fetch(apiUrl, requestOptions)
.then((response) => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.then((data) => {
// 显示获取的用户数据
userProfileElement.innerHTML = `
<p><strong>Name:</strong> ${data.name}</p>
<p><strong>Email:</strong> ${data.email}</p>
<p><strong>Website:</strong> ${data.website}</p>
`;
})
.catch((error) => {
userProfileElement.textContent = "Failed to load user profile.";
console.error("Error:", error);
});
在这段代码中:
- 我们定义了一个占位符
apiKey。 - 我们创建了一个
requestOptions对象。 - 在
headers中,我们添加了一个Authorization键。值Bearer ${apiKey}是一种常见的格式,其中“Bearer”是令牌类型,后面跟着密钥本身。
注意: 我们正在使用的 JSONPlaceholder API 是公开的,实际上不需要 API 密钥。它只会忽略此标头。但是,此代码演示了你将用于许多需要认证的真实 API 的标准方法。
要查看结果,如果你的 Web 服务器尚未运行,请启动它:
python3 -m http.server 8080
然后,打开预览。页面将成功加载并显示用户的配置文件,这表明你已正确构建了一个已认证的 API 请求。
总结
在本实验中,你学习了如何使用现代的 fetch API 在 JavaScript 中调用 API。你首先向公共 API 端点发出基本的 GET 请求来检索数据。你通过使用 Promises、链式调用 .then() 块来处理响应并将响应体解析为 JSON,从而练习了处理 fetch 的异步特性。关键技能包括在 HTML 元素中动态显示获取的数据,以及使用 .catch() 块实现健壮的错误处理来管理潜在的网络故障。
在此基础上,你通过构建和执行 POST 请求,包括必要的标头和 JSON 载荷,探索了如何将数据发送到服务器。最后,你学习了一种通过认证请求来保护 API 通信的常用方法,这涉及到包含 API 密钥以获得对受保护资源的授权访问。



