第4.3章:发送 POST/PUT/DELETE 请求
学习时间: 1 小时
1. 主动命令:从启动到报废
迄今为止,我们的控制中心只请求信息 (GET
)。现在我们将学习发送主动命令:
- POST:“将新卫星发射到轨道!”
- PUT:“对国际空间站系统进行全面升级!”
- DELETE:“将旧设备
Debris-123
脱离轨道!”
为此,我们将使用 fetch
,但会附加描述我们命令的额外参数。
💡 太空类比:
如果
GET
是被动监听无线电信号,那么POST
、PUT
和DELETE
则是主动发送命令。为此,我们不仅需要指定“频率”(URL),还需要指定命令内容(请求体)和通信协议(请求头)。
2. 发送 POST 请求:启动新飞船
为了创建新资源,我们发送 POST
请求。最重要的是传递包含新对象数据的请求体 (body)。
步骤 1:在 index.html
中添加创建表单
将其放置在“按 ID 请求”块之后。
<!-- index.html -->
<hr>
<h2>启动新设备</h2>
<form id="create-ship-form">
<input type="text" id="create-name" placeholder="名称" required><br>
<input type="text" id="create-type" placeholder="类型" required><br>
<input type="number" id="create-year" placeholder="发射年份" required><br>
<input type="text" id="create-status" placeholder="状态" required><br>
<button type="submit">启动</button>
</form>
<div id="create-status-message"></div>
步骤 2:在 app.js
中添加逻辑
// app.js,文件末尾
const createShipForm = document.getElementById('create-ship-form');
const createStatusMessage = document.getElementById('create-status-message');
async function createShip(event) {
event.preventDefault();
// 1. 将表单数据收集到对象中
const shipData = {
name: document.getElementById('create-name').value,
type: document.getElementById('create-type').value,
launch_year: parseInt(document.getElementById('create-year').value),
status: document.getElementById('create-status').value
};
try {
createStatusMessage.textContent = '正在发送启动命令...';
// 2. 发送带参数的 fetch 请求
const response = await fetch(`${API_BASE_URL}/spaceships`, {
method: 'POST', // 指定方法
headers: {
'Content-Type': 'application/json' // 告诉服务器我们发送的是 JSON
},
body: JSON.stringify(shipData) // 将 JavaScript 对象转换为 JSON 字符串
});
if (!response.ok) {
// 如果服务器返回错误,尝试读取其响应体
const errorData = await response.json();
throw new Error(errorData.detail || `服务器错误:${response.status}`);
}
const newShip = await response.json();
createStatusMessage.textContent = `🚀 成功启动!设备 ID 已分配:${newShip.id}`;
createShipForm.reset(); // 清空表单
fetchAndDisplayFleet(); // 更新舰队总列表
} catch (error) {
console.error('启动设备时出错:', error);
createStatusMessage.textContent = `🔴 错误:${error.message}`;
}
}
createShipForm.addEventListener('submit', createShip);
fetch
的关键点:
method: 'POST'
: 必须指定 HTTP 方法。headers: { 'Content-Type': 'application/json' }
: 极其重要的请求头。它告诉我们的 FastAPI 服务器请求体中包含 JSON,需要进行解析。body: JSON.stringify(shipData)
: 我们不能直接发送 JavaScript 对象。需要将其序列化(转换)为 JSON 字符串。
3. 发送 DELETE 请求:设备报废
删除请求更简单——它通常不需要请求体,只需带有对象 ID 的 URL。
步骤 1:在我们的飞船列表中添加“删除”按钮
修改 app.js
中的 fetchAndDisplayFleet
函数,使其为每个元素添加删除按钮。
// app.js,在 fetchAndDisplayFleet 函数内部
// ...
ships.forEach(ship => {
const listItem = document.createElement('li');
// 添加一个带有存储 ID 的 data 属性的按钮
listItem.innerHTML = `
<strong>${ship.name} (ID: ${ship.id})</strong><br>
类型:${ship.type} | 年份:${ship.launch_year} | 状态:${ship.status}<br>
<button class="delete-btn" data-ship-id="${ship.id}">报废设备</button>
`;
fleetList.appendChild(listItem);
});
// ...
步骤 2:为所有“删除”按钮添加处理程序 我们使用事件委托——为整个列表设置一个处理程序。
// app.js,文件末尾
async function deleteShip(shipId) {
if (!confirm(`您确定要报废 ID 为 ${shipId} 的设备吗?此操作不可逆。`)) {
return;
}
try {
const response = await fetch(`${API_BASE_URL}/spaceships/${shipId}`, {
method: 'DELETE' // 指定方法
});
if (!response.ok) {
throw new Error(`无法报废设备。状态:${response.status}`);
}
alert(`ID 为 ${shipId} 的设备已成功报废。`);
fetchAndDisplayFleet(); // 更新列表
} catch (error) {
console.error('报废时出错:', error);
alert(`错误:${error.message}`);
}
}
// 事件委托:监听整个列表的点击事件
fleetList.addEventListener('click', (event) => {
// 检查点击是否发生在类名为 'delete-btn' 的按钮上
if (event.target.classList.contains('delete-btn')) {
const shipId = event.target.dataset.shipId; // 从 data 属性获取 ID
deleteShip(shipId);
}
});
步骤 3:在 Spaceship 模型中添加 id
在 main.py
文件中的模型和数据库中添加 id
class Spaceship(BaseModel):
id: int
# 模型的其余代码...
db_spaceships = {
1: {
"id": 1,
# 元素 1 的数据
},
2: {
"id": 2,
# 元素 2 的数据
},
3: {
"id": 3,
# 元素 3 的数据
}
}
method: 'DELETE'
: 指定方法。这里不需要请求体和请求头。confirm()
:一个简单的内置确认窗口,以防意外删除重要内容。
4. 发送 PUT 请求(自学任务)
实现 PUT
请求进行更新与 POST
非常相似。
您的任务,如果您选择接受它:
- 为每艘飞船在“删除”按钮旁边添加一个“修改”按钮。
- 点击“修改”时,使用飞船的当前数据填充表单(可以使用创建表单)。
- 将“启动”按钮的文本更改为“更新”。
- 提交表单时,向
/spaceships/{id}
发送PUT
请求,并附带完整的对象体。 - 成功更新后,更新舰队列表。
提示: 您将需要使用
method: 'PUT'
、Content-Type
请求头和带有JSON.stringify()
的body
来发送fetch
请求,就像在POST
请求中一样。
巩固测验
🚀 本章总结:
您的任务控制中心现在拥有了管理舰队的完整指令集!
- ✅ 您学会了发送带有请求体和请求头的
POST
请求来创建新资源。 - ✅ 您实现了
DELETE
请求来报废旧设备。 - ✅ 您收到了实现
PUT
请求的任务,巩固了您的知识。
全面控制已建立! 但如果通信中断或服务器报告错误怎么办?在下一章中,我们将在前端创建一个集中的错误处理系统。
📌 检查:
- 确保创建新飞船的表单正常工作,并在成功创建后页面上的列表得到更新。
- 检查“报废设备”按钮是否工作,是否请求确认,并从列表中删除飞船。
- 尝试使用无效数据(例如,名称非常短)创建飞船,并查看您的 FastAPI 服务器将返回的错误。
⚠️ 如果有错误:
- 服务器返回
422
错误: 很可能您发送的数据未通过 Pydantic 验证。检查浏览器控制台 —errorData.detail
将显示哪个字段有问题。415 Unsupported Media Type
错误: 您忘记添加'Content-Type': 'application/json'
请求头。- 删除按钮不起作用: 检查事件委托是否正确工作,以及您是否正确从
data-ship-id
获取了shipId
。