Skip to content

第4.2章:发送 GET 请求

学习时间: 45 分钟


1. GET:从太空舰队请求遥测数据

GET 请求 是获取数据的基本命令。在我们的任务控制中心,这相当于发出请求:“舰队控制中心,报告当前情况!”

我们将使用 fetch 向我们的 FastAPI 服务器发送两种类型的 GET 请求:

  1. 获取整个集合: “给我看我的整个舰队。”
  2. 获取单个资源: “给我 ID 为 2 的飞船的详细信息。”

💡 太空类比:

GET /spaceships 是向整个舰队发出的广播请求,要求它们报告自己的呼号。

GET /spaceships/3 是向特定飞船(国际空间站)发出的定向请求,要求它传输其系统的完整数据。


2. CORS 问题:“行星际干扰”

在我们发送请求之前,需要解决一个重要问题。默认情况下,出于安全考虑,浏览器禁止从一个“域” (file:///...http://localhost:5500) 加载的网页(我们的任务控制中心)向另一个“域” (http://127.0.0.1:8000) 上的 API 发出请求。

此策略称为 CORS (跨域资源共享)

为了允许我们的前端与后端通信,需要配置 FastAPI 服务器,使其告诉浏览器:“没问题,我信任来自该地址的请求。”

步骤 1:安装 python-multipart 这对于中间件的正常运行是必需的。

pip install python-multipart

步骤 2:在 main.py 中配置 CORS 打开您的 FastAPI 项目中的 main.py 文件,并添加以下代码:

# main.py
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware  # <-- 导入中间件

# ... 您的其余代码(模型、db_spaceships) ...

app = FastAPI(
    title="Fleet Management API",
    # ...
)

# --- CORS 配置 ---
# 指定哪些“域”(origins)可以发送请求
origins = [
    "http://localhost",
    "http://localhost:8080",
    "http://127.0.0.1:5500",  # VS Code 中 Live Server 的地址
    "null"  # 用于来自本地文件 file:/// 的请求
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,  # 允许指定的源
    allow_credentials=True,
    allow_methods=["*"],  # 允许所有方法(GET、POST 等)
    allow_headers=["*"],  # 允许所有头部
)

# --- 您的端点在下方 ---
@app.get("/")
# ...
现在,我们的 API 服务器已准备好接收来自前端的请求。请重新启动 uvicorn,以使更改生效!


3. 获取所有飞船列表

我们将创建一个接口来显示我们的舰队。

步骤 1:更新 index.html

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>任务控制中心 - 舰队管理</title>
    <style>
        body { font-family: sans-serif; }
        .ship-list { list-style: none; padding: 0; }
        .ship-list li { border: 1px solid #ccc; margin-bottom: 10px; padding: 15px; border-radius: 5px; }
    </style>
</head>
<body>
    <h1>太空舰队控制面板</h1>

    <button id="load-fleet-btn">请求舰队数据</button>

    <h2>飞行器列表:</h2>
    <ul id="fleet-list" class="ship-list">
        <li>等待命令...</li>
    </ul>

    <script src="app.js"></script> <!-- 连接外部脚本 -->
</body>
</html>

步骤 2:创建 app.jsindex.html 旁边创建一个 app.js 文件。我们将所有逻辑都放在其中。

// app.js

const API_BASE_URL = 'http://127.0.0.1:8000'; // 我们的 FastAPI 服务器的 URL

const loadFleetBtn = document.getElementById('load-fleet-btn');
const fleetList = document.getElementById('fleet-list');

// 加载和显示舰队的函数
async function fetchAndDisplayFleet() {
    try {
        fleetList.innerHTML = '<li>正在加载遥测数据...</li>';

        // 向 /spaceships 发送 GET 请求
        const response = await fetch(`${API_BASE_URL}/spaceships`);

        if (!response.ok) {
            throw new Error(`网络错误:${response.status}`);
        }

        const ships = await response.json(); // 获取飞船数组

        // 清空列表并显示数据
        fleetList.innerHTML = '';
        if (ships.length === 0) {
            fleetList.innerHTML = '<li>注册表中没有任何飞行器。</li>';
            return;
        }

        ships.forEach(ship => {
            const listItem = document.createElement('li');
            listItem.innerHTML = `
                <strong>${ship.name} (ID: ${ship.id})</strong><br>
                类型:${ship.type}<br>
                发射年份:${ship.launch_year}<br>
                状态:${ship.status}
            `;
            fleetList.appendChild(listItem);
        });

    } catch (error) {
        console.error('无法加载舰队数据:', error);
        fleetList.innerHTML = `<li>错误:${error.message}</li>`;
    }
}

// 为按钮添加事件处理程序
loadFleetBtn.addEventListener('click', fetchAndDisplayFleet);

  • async/await: 我们使用了处理 Promise 的新且更便捷的语法。我们将在第 4.5 章中详细探讨它。现在您只需知道 await 会“等待” Promise 的完成,而不会阻塞页面。
  • try...catch:处理 async 函数中错误的好方法。

步骤 3:测试 在浏览器中打开 index.html(最好通过 VS Code 中的 Live Server 扩展,它会将其运行在 http://127.0.0.1:5500)。点击“请求舰队数据”按钮。您来自 FastAPI 的飞船列表应该会显示在页面上!


4. 获取单个飞船的数据

现在,我们将添加一个表单,用于按特定 ID 请求信息。

步骤 1:在 index.html 中添加表单

<!-- index.html,在列表之后 -->
<hr>
<h2>按 ID 请求</h2>
<form id="ship-form">
    <input type="number" id="ship-id-input" placeholder="请输入飞行器 ID" required>
    <button type="submit">查找飞行器</button>
</form>
<div id="ship-details" class="ship-list"></div>

步骤 2:在 app.js 中添加逻辑

// app.js,文件末尾

const shipForm = document.getElementById('ship-form');
const shipIdInput = document.getElementById('ship-id-input');
const shipDetails = document.getElementById('ship-details');

async function fetchShipById(event) {
    event.preventDefault(); // 阻止页面重新加载
    const shipId = shipIdInput.value;

    if (!shipId) {
        alert('请输入 ID。');
        return;
    }

    try {
        shipDetails.innerHTML = '<li>正在搜索飞行器...</li>';

        // 向 /spaceships/{id} 发送 GET 请求
        const response = await fetch(`${API_BASE_URL}/spaceships/${shipId}`);

        if (response.status === 404) {
             throw new Error('注册表中未找到 ID 为此的飞行器。');
        }
        if (!response.ok) {
            throw new Error(`网络错误:${response.status}`);
        }

        const ship = await response.json();

        shipDetails.innerHTML = `
            <li>
                <strong>${ship.name} (ID: ${ship.id})</strong><br>
                类型:${ship.type}<br>
                发射年份:${ship.launch_year}<br>
                状态:${ship.status}
            </li>
        `;
    } catch (error) {
        console.error(`搜索飞行器时出错 ${shipId}:`, error);
        shipDetails.innerHTML = `<li>错误:${error.message}</li>`;
    }
}

shipForm.addEventListener('submit', fetchShipById);

  • 我们添加了对 404 状态码的单独处理,以便为用户提供更清晰的错误消息。

步骤 3:测试 刷新页面,输入现有飞船的 ID(例如,1),然后点击“查找飞行器”。您应该能看到它的数据。尝试输入一个不存在的 ID(例如,99)——您将看到错误消息。


巩固测验

1. 浏览器中的 CORS 策略用于...

2. 要允许 `localhost:5500` 上的前端访问 FastAPI,需要...

3. 要获取 ID=5 的特定资源的数据,请求 URL 将如下所示:

4. JavaScript 中的关键字 `await` 只能在用...声明的函数内部使用。

5. 表单提交处理程序中的 `event.preventDefault()` 用于...


🚀 本章总结:

您已成功设置“地球”与“太空”之间的通信信道,并学会了请求遥测数据!

  • 🛡️ 您通过在 FastAPI 服务器上配置 CORS 解决了“行星际干扰”问题。
  • 🛰️ 实现了一个函数,用于获取和显示所有航天器的完整列表
  • 🔭 创建了一个界面,用于通过 ID 请求特定航天器的数据。

任务控制中心正在接收数据! 在下一章中,我们将进入实战环节:发送命令来创建、更新和删除我们的宇宙飞船。

📌 检查:

  • 确保您的 FastAPI 服务器已启动并配置了 CORSMiddleware
  • 检查在页面上点击“请求数据”按钮时是否出现飞船列表。
  • 确保按 ID 搜索的表单能正确找到现有设备,并对不存在的设备报告错误。

⚠️ 如果出现错误:

  • 浏览器控制台中出现 CORS 错误: 您可能在添加 CORSMiddleware 后未重新启动 uvicorn,或者您的前端地址(例如 http://127.0.0.1:5500)未添加到 origins 列表中。
  • Failed to fetch: 检查您的 FastAPI 服务器是否已启动并可通过 API_BASE_URL 中指定的地址访问。