Menu
CoddyTech

调用 API 的页面

本课属于 Coddy Node.js 学习旅程的“REST API”单元。第 21 课,共 25 课。

页面会使用 fetch 调用你的 API。POST 请求需要三个选项:方法、标头和请求体。将 JavaScript 对象转换为 JSON 文本作为请求体,并将该文本标记为 application/json。

const response = await fetch('/api/books', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({title: title}),
});
const data = await response.json();

第一个 await 接收 HTTP 响应。第二个读取响应的 JSON 请求体。response.ok 会告诉你响应状态是否处于成功范围内。像 400 或 409 这样的状态不会导致 fetch promise 被拒绝;它会返回一个 ok 为 false 的响应。表单和列表代码已提供,你只需专注于发送请求并处理结果。

提供的 message 变量指向页面上的消息段落。设置它的 textContent 来显示文本,或者将其设为空字符串以清除内容:

message.textContent = data.error.message;
// 成功后清空它:
message.textContent = '';

页面和 API 使用相同的来源,因此此调用不需要 CORS 权限。FormData 对表单的编码方式与 JSON 不同;请使用 JSON 文本,因为此 API 使用 express.json()。

challenge icon

挑战

简单

你的 API 还没有页面。为它添加一个简单的页面,由同一台服务器提供,其中的表单通过 API 添加任务。

  1. 在 server.js 中,使用 express.static 提供 public 文件夹,这样 GET / 就会返回 public/index.html。
  2. 在 public/index.html 中,提交事件监听器已经读取了标题。让它把新任务发送到 API:
    • 使用包含输入文本的 title 变量。
    • 使用 fetch('/api/tasks', ...) 发送 POST 请求。
    • 请求正文是用 JSON.stringify 生成的 JSON 文本,例如 {"title":"Water the plants"}。
    • 请求需要在 fetch 的 headers 选项中设置请求头 'Content-Type': 'application/json',否则 express.json() 将无法读取请求正文。
  3. 如果响应正常(对于 200 到 299 之间的任何状态码,其 ok 属性都为 true),就用 form.reset() 清空表单,清空 #message,然后调用 load(),让列表显示新任务。
  4. 否则,响应正文采用之前介绍过的错误格式,例如:
    { "error": { "code": "conflict", "message": "A task with this title already exists" } }
    在 #message 段落中显示其中的 message。

检查会使用一个简单的模拟表单和真实的课内 API 来执行这个提供的页面脚本。它们会提交一个任务和一个重复任务,然后检查列表、表单和消息。也可以在编辑器旁边试试实际页面。

试试看:发送 GET /。页面会在页面视图中打开,其中显示 3 个初始任务。输入 "Water the plants" 并按 Add:输入框会清空,任务会出现在列表底部。再次输入 "Water the plants" 并按 Add:列表保持不变,表单下方会显示 "A task with this title already exists"。

亲手试试

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Tasks</title>
</head>
<body>
    <h1>Tasks</h1>
    <ul id="list"></ul>
    <form id="add">
        <input name="title" placeholder="New task" required>
        <button>Add</button>
    </form>
    <p id="message"></p>
    <script>
        const list = document.querySelector('#list');
        const form = document.querySelector('#add');
        const message = document.querySelector('#message');

        async function load() {
            const response = await fetch('/api/tasks?limit=50');
            const page = await response.json();
            list.replaceChildren(...page.items.map((task) => {
                const item = document.createElement('li');
                item.textContent = (task.done ? '[x] ' : '[ ] ') + task.title;
                return item;
            }));
        }

        form.addEventListener('submit', async (event) => {
            event.preventDefault();
            const title = form.elements.title.value;
            // Send the title to POST /api/tasks as JSON. On success clear
            // the form and load() again; on an error show its message.
        });

        load();
    </script>
</body>
</html>

REST API中的所有课

自己练习: Express 在线编辑器