【Python精讲 16】实战项目演练(二):用Flask/FastAPI发布你的第一个Web API - 详解

news/2025/10/15 11:05:08/文章来源:https://www.cnblogs.com/slgkaifa/p/19142851

【Python精讲 16】实战项目演练(二):用Flask/FastAPI发布你的第一个Web API - 详解

摘要:我们已经学会了如何从网上“获取”数据,现在是时候学习如何向外“提供”数据和服务了。本文将带你使用一个轻量级的Web框架(以FastAPI为例,它更现代且自带文档),亲手创建一个简单的Web API。这个API可以接收网络请求,执行Python逻辑,并返回JSON格式的数据。这不仅是后端开发的入门,更是让你编写的任何脚本都能通过网络被调用的关键一步。

前言:让你的代码“上线”

你写了一个很酷的Python脚本,比如一个能根据输入文本生成摘要的函数。现在,你想让你的朋友,甚至全世界的人都能使用它,但他们并没有Python环境。怎么办?

最好的方式就是把它包装成一个Web API (Application Programming Interface)

  • API:就像一个餐厅的服务员。你(客户端)不需要知道后厨(服务器逻辑)是怎么运作的,你只需要按照菜单(API文档)告诉服务员你想要什么(发送一个HTTP请求),服务员就会把菜(JSON数据)端给你。
  • Web框架 (Flask/FastAPI):就是一套标准化的“厨房设备和管理流程”。它帮你处理了所有繁琐的底层网络细节(如处理HTTP请求、路由分发),让你能专注于烹饪(编写核心业务逻辑)。

我们将使用FastAPI,因为它非常快、易于学习,并且能自动生成交互式的API文档,对新手极其友好。

安装必要的库

pip install fastapi
pip install uvicorn[standard] # uvicorn是一个运行FastAPI应用的服务器

一、项目目标

我们将创建一个简单的“城市信息查询”API,它将具备以下功能:

  1. 根路径 (/): 访问时返回一个欢迎信息。
  2. 城市列表 (/cities): 响应一个包含多个城市信息的列表。
  3. 特定城市查询 (/cities/{city_id}): 根据传入的城市ID,返回该城市的详细信息。如果城市不存在,返回一个错误信息。

二、代码实现

  1. 创建一个名为 main.py 的文件。
  2. 将以下所有代码复制到 main.py 中。
# main.py
from fastapi import FastAPI, HTTPException
from fastapi.responses import Response, HTMLResponse
# 1. 创建 FastAPI 实例
# 这就是我们的Web应用核心
app = FastAPI(
title="城市信息API",
description="一个用于查询城市信息的简单API",
version="1.0.0",
)
# 简单的内联 SVG 作为 favicon(避免二进制 .ico 文件)
FAVICON_SVG = """
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><linearGradient id="g" x1="0" y1="0" x2="1" y2="1"><stop offset="0%" stop-color="#4f46e5"/><stop offset="100%" stop-color="#22d3ee"/></linearGradient></defs><rect width="64" height="64" rx="12" fill="url(#g)"/><path d="M20 44c0-8 6-14 14-14h4v-6h6v26h-6v-8h-4c-2.2 0-4 1.8-4 4v4h-6v-6z" fill="#ffffff"/>
</svg>
"""
# 2. 准备一些模拟数据
# 在真实项目中,这些数据可能来自数据库
CITIES_DB = {
1: {"name": "北京", "population": 2189, "country": "中国"},
2: {"name": "东京", "population": 3739, "country": "日本"},
3: {"name": "纽约", "population": 839, "country": "美国"},
}
# 3. 定义路由和处理函数
# 提供 /favicon.ico,避免浏览器请求 404
@app.get("/favicon.ico")
def favicon():
return Response(content=FAVICON_SVG, media_type="image/svg+xml")
# 优化后的可视化首页:展示城市列表、按ID查询,并链接到Swagger文档
@app.get("/", response_class=HTMLResponse)
def read_root():
html = """
<!DOCTYPE html><html lang=\"zh-CN\"><head><meta charset=\"utf-8\" /><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" /><title>城市信息 API 演示</title><style>:root { --bg: #0f172a; --card:#0b1220; --text:#e5e7eb; --muted:#9aa0aa; --primary:#22d3ee; --accent:#4f46e5; }* { box-sizing: border-box; }body { margin:0; font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial; background: linear-gradient(180deg, #0b1020, #0f172a); color: var(--text); }header { padding: 28px 20px; background: linear-gradient(90deg, var(--accent), var(--primary)); color: white; }.wrap { max-width: 1100px; margin: 0 auto; }h1 { margin: 0; font-size: 24px; font-weight: 700; letter-spacing: .5px; }main { padding: 26px 16px 40px; }.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 16px; }.card { background: rgba(255,255,255,0.04); border: 1px solid rgba(255,255,255,0.06); border-radius: 14px; padding: 16px; backdrop-filter: blur(6px); box-shadow: 0 8px 22px rgba(0,0,0,.25); }.card h3 { margin: 0 0 8px; font-size: 18px; }.muted { color: var(--muted); font-size: 13px; }.row { display:flex; gap: 16px; flex-wrap: wrap; margin-bottom: 18px; }.panel { flex: 1 1 320px; background: rgba(255,255,255,0.04); border: 1px solid rgba(255,255,255,0.06); border-radius: 14px; padding: 16px; }label { display:block; margin-bottom: 8px; color: var(--muted); }input { width: 100%; padding: 10px 12px; border-radius: 10px; border: 1px solid rgba(255,255,255,.15); background: rgba(255,255,255,.06); color: var(--text); outline: none; }button { margin-top: 8px; padding: 10px 14px; border: none; border-radius: 10px; color:#0b1020; background: linear-gradient(90deg, var(--primary), var(--accent)); cursor: pointer; font-weight: 600; }button:disabled { opacity: .6; cursor: not-allowed; }.result { margin-top: 10px; font-size: 14px; }footer { text-align:center; padding: 18px; color: var(--muted); border-top: 1px solid rgba(255,255,255,.06); }a { color: #7dd3fc; text-decoration: none; }a:hover { text-decoration: underline; }</style></head><body><header><div class=\"wrap\"><h1>城市信息 API 演示</h1></div></header><main class=\"wrap\"><div class=\"row\"><section class=\"panel\" style=\"min-height:160px\"><h2 style=\"margin:0 0 10px\">按 ID 查询</h2><label for=\"cityId\">输入城市 ID(例如 1、2、3)</label><input id=\"cityId\" placeholder=\"如:1\" /><button id=\"btnQuery\">查询</button><div id=\"queryResult\" class=\"result muted\">等待查询...</div></section><section class=\"panel\"><h2 style=\"margin:0 0 10px\">API 文档</h2><p class=\"muted\">你可以在 <a href=\"/docs\" target=\"_blank\">/docs</a> 查看交互式接口文档(Swagger UI)。</p><p class=\"muted\">或者直接访问 <a href=\"/api\" target=\"_blank\">/api</a> 获取欢迎信息(JSON)。</p></section></div><section><h2 style=\"margin:6px 0 12px\">城市列表</h2><div id=\"cityList\" class=\"grid\"></div></section></main><footer>由 FastAPI 提供服务 · 示例数据仅用于演示</footer><script>async function loadCities() {const container = document.getElementById('cityList');container.innerHTML = '<div class="muted">加载中...</div>';try {const res = await fetch('/cities');const data = await res.json();if (!Array.isArray(data)) throw new Error('响应格式不正确');container.innerHTML = data.map((c, idx) => `<div class="card"><h3>${c.name}</h3><div class="muted">国家/地区:${c.country}</div><div class="muted">人口(万):${c.population}</div><div class="muted">序号:${idx + 1}</div></div>`).join('');} catch (e) {container.innerHTML = '<div class="muted">加载失败:' + (e.message || e) + '</div>'}}async function queryById() {const id = document.getElementById('cityId').value.trim();const btn = document.getElementById('btnQuery');const result = document.getElementById('queryResult');if (!id) { result.textContent = '请输入城市ID'; return; }btn.disabled = true; result.textContent = '查询中...';try {const res = await fetch('/cities/' + encodeURIComponent(id));if (res.ok) {const data = await res.json();result.innerHTML = `<b>${data.name}</b> · 国家/地区:${data.country} · 人口(万):${data.population}`;} else if (res.status === 404) {const j = await res.json();result.textContent = '未找到:' + (j.detail || '城市不存在');} else {result.textContent = '请求失败:' + res.status;}} catch (e) {result.textContent = '网络错误:' + (e.message || e);} finally {btn.disabled = false;}}document.getElementById('btnQuery').addEventListener('click', queryById);loadCities();</script></body>
</html>
"""
return HTMLResponse(content=html)
# 保留原本欢迎信息(JSON)在 /api
@app.get("/api")
def api_root():
return {"message": "欢迎使用城市信息查询API!"}
# 路由:/cities
@app.get("/cities")
def get_cities():
"""
返回所有城市信息的列表。
"""
return list(CITIES_DB.values())
# 路由:/cities/{city_id}
# {city_id} 是一个“路径参数”,它的值会被传给函数的同名参数
@app.get("/cities/{city_id}")
def get_city_by_id(city_id: int):
"""
根据城市ID查询特定城市的信息。
- **city_id**: 要查询的城市ID (整数)。
"""
city = CITIES_DB.get(city_id)
if not city:
# 如果在数据库中找不到城市,抛出一个HTTP 404错误
raise HTTPException(status_code=404, detail=f"ID为 {city_id} 的城市未找到")
return city
# 假设我们还想添加一个新城市 (POST请求)
@app.post("/cities")
def create_city(name: str, population: int, country: str):
"""
创建一个新城市。
(这是一个简单的示例,不会真的保存)
"""
new_id = max(CITIES_DB.keys()) + 1
new_city = {"name": name, "population": population, "country": country}
# 在真实应用中,这里会执行 CITIES_DB[new_id] = new_city 并保存到数据库
print(f"模拟创建新城市: ID={new_id}, Data={new_city}")
return {"message": "城市创建成功(模拟)", "city_id": new_id, "data": new_city}

三、运行与测试你的API

3.1 启动服务器

在你的终端中,进入 main.py 所在的目录,然后运行以下命令:

uvicorn main:app --reload
  • main: 指的是 main.py 文件。
  • app: 指的是我们在代码中创建的 FastAPI 实例 app = FastAPI()
  • --reload: 这个参数非常有用,它会让服务器在你修改并保存代码后自动重启。

如果一切顺利,你会看到类似这样的输出:

INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)

这表明你的API服务器已经在你的本地 8000 端口上运行了!

请添加图片描述

3.2 使用自动生成的交互式文档进行测试 (FastAPI的魅力!)

现在,打开你的浏览器,访问以下两个URL中的任意一个:

你会看到一个精美的、可交互的API文档页面。FastAPI自动根据你的Python代码生成了这一切!

请添加图片描述

在这个页面上,你可以:

  1. 看到你定义的所有API“端点”(Endpoints)。
  2. 展开每一个端点,查看它的详细说明、参数、可能的响应。
  3. 点击 “Try it out” 按钮,直接在浏览器中输入参数,然后点击 “Execute” 发送请求,并立即看到真实的服务器响应!

尝试一下


总结

恭喜你,你已经成功地构建并发布了一个Web API!虽然它很简单,但它包含了后端开发的全部核心要素:

  • Web框架:使用FastAPI处理网络请求。
  • 路由:通过@app.get等装饰器,将URL路径映射到具体的处理函数。
  • 业务逻辑:在处理函数中编写你的Python代码(如从CITIES_DB中查询数据)。
  • 数据交换:自动将Python字典和列表转换为客户端需要的JSON格式。
  • 错误处理:通过HTTPException向客户端返回清晰的错误信息。

现在,你的任何Python代码,无论是复杂的机器学习模型,还是一个简单的数据计算脚本,都可以通过这种方式包装成一个服务,被网页、手机App或其他任何能上网的程序所调用。你已经打开了通往后端开发和服务化编程的大门。

预告:【Python精讲 完结】技术栈梳理:从Python开发者到专家的进阶之路

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/937341.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于遗传算法的33节点微电网网络重构优化

一、系统建模与参数配置 1. 33节点配电网拓扑 +-------------------+| 33节点主网架 || (IEEE标准结构) |+--------+----------+|v +-------------------+ +-------------------+ | 分布式电源 …

PMTU机制原理和缺陷

PMTU 机制原理 PMTU(Path Maximum Transmission Unit,路径最大传输单元)发现机制 是一种用于动态探测从源主机到目的主机之间整条网络路径上最小 MTU 值的技术,目的是避免 IP 数据包在传输过程中被分片。 ✅ 核心目…

2025 年摇臂钻床厂商最新推荐排行榜:含 3050/3080/3040/3063/50 型号厂家产能与供应优势详解

当前制造业加速向智能化、高效化转型,摇臂钻床作为机械加工核心设备,其品质与供应效率直接决定下游企业生产进度与产品精度。但市场中供应商数量繁杂,部分厂商存在产能不足导致交货延迟、技术落后无法满足定制需求、…

Linux进程 --- 2 - 实践

Linux进程 --- 2 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", &qu…

20232402 2025-2026-1 《网络与系统攻防技术》实验一实验报告

20232402 2025-2026-1 《网络与系统攻防技术》实验一实验报告 1.实验内容 本周学习内容为缓冲区溢出漏洞简介和缓冲区溢出基础知识。 1.1 缓冲区溢出漏洞简介缓冲区是连续的一段存储空间。 缓冲区溢出是指向特定缓冲区…

2025 年最新推荐排水沟厂家排行榜:聚焦树脂 / 线性 / 树脂混凝土 / 成品 /u 型排水沟优质厂家推荐

在市政工程、电厂建设、道路施工等基础设施项目中,排水沟的质量与性能直接关乎工程稳定性和使用寿命。当前市场上排水沟产品质量参差不齐,部分产品存在强度不足、易腐蚀、安装后异响移位等问题,增加后期维护成本且埋…

2025 年最新推荐排水沟厂家排行榜:聚焦树脂 / 线性 / 树脂混凝土 / 成品 /u 型排水沟优质厂家推荐

在市政工程、电厂建设、道路施工等基础设施项目中,排水沟的质量与性能直接关乎工程稳定性和使用寿命。当前市场上排水沟产品质量参差不齐,部分产品存在强度不足、易腐蚀、安装后异响移位等问题,增加后期维护成本且埋…

2025 年盖板源头厂家最新推荐榜单:涵盖电力 / 隧道 / 扣槽 / 室内外电缆沟 / 复合及树脂盖板,深度解析源头厂家原材料采购与成本控制

当前盖板行业应用场景持续拓展,从市政工程到电厂、高速、隧道等领域,对盖板的质量、性能及成本要求愈发严苛。但市场上部分厂家存在原材料把控不严、成本控制失衡、定制服务滞后等问题,导致采购方难以精准筛选优质合…

AC6966B SD配置F组可以吗?ok

虽然《Jieli-AC6966B-V1.0.pdf》只标明了PB7可以做SD CLK,但实测是可以读卡的。 如果读不到ID请检查芯片是否贴好。

2025 年最新紫外线灯厂家推荐排行榜:优质厂家权威榜单发布,含杀菌灯消毒灯选购指南

当前,紫外线灯在空气净化、水处理、食品医药等领域的应用愈发广泛,市场需求持续增长,但行业乱象也随之凸显。众多品牌涌入市场,产品质量差异悬殊,部分产品存在使用寿命短、光衰快、紫外线输出不稳定等问题,严重影…

trading platform

每天拥有超过6万亿美刀交易额的市场,你知道它衍生出多少平台吗?今天我们来盘点一下最牛的十大外汇经纪商。 作为杠杆投资,外汇交易又是收益和风险并存的。所以一个优质安全的平台,从搭建到完善,必须时刻考虑交易系…

GDB 与 GDBServer 远程调试基础命令详解

GDB 与 GDBServer 远程调试基础命令详解 ​一、环境准备​​目标机(嵌入式设备)​​安装 gdbserver(如 arm-linux-gnueabihf-gdbserver)启动 gdbserver并监听端口:bashbash复制gdbserver :2345 /path/to/program …

zedboard + AD-FMCOMMS3-EBZ AD9361 (三) matlab demo 测试

zedboard + AD-FMCOMMS3-EBZ AD9361 (三) matlab demo 测试 AMD FPGA and SoC Devices — Examples

内网穿透的原理和安装

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

.NET 构架下remoting和webservice

“WebService 走 HTTP+SOAP,跨平台却低效;Remoting 走 TCP/二进制,高效但仅限 .NET。二者都已被 WCF → gRPC/WebAPI 取代,如今只出现在遗产系统。

SIMATIC WinCC V8.1 安装教程与功能介绍(附详细图文步骤)超详细

SIMATIC WinCC V8.1是西门子公司推出的先进的过程监视和控制系统软件。它基于Windows操作系统,继承了前几代产品的优良特性。该软件提供更好的兼容性,能支持更多硬件设备和控制系统。拥有现代化的Web UI,用户可通过…

Zerotier,内网穿透神器 - IT苦行僧

zerotier是基于点对点的网络链接速度只取决于自己的网络带宽,可以让你轻松自如地实现远程办公。下面就跟着我的图文教程一步步搭建你的zerotier网络吧。首先登录zerotier官网,注册账号,建立网络,下载客户端软件官网…

311、出塞

311、出塞311、出塞 唐●王之涣 黄河远上白云间,一片孤城万仞山。 羌笛何须怨杨柳,春风不度玉门关。【现代诗意译】 远远望云 黄河与天上的白云连在一起 下面是一片孤零零的戍城 坐落在万仞高山下吹笛的将士们啊 你们…

接触过的芯片型号之间区别

接触过的芯片型号之间区别1.RK3568,RK3506,ESP8266,ESP32,MCS-51之间有什么不同?特性 MCS-51 ESP8266/ESP32 RK3568 / RK3506核心类别 微控制器 微控制器 应用处理器核心架构 8位/16位 单核 32位 单核/双核 (Xtens…

PCL2 下载安装全攻略:整合包导入 + Mod安装 + 常见问题汇总(2025最新版)

想快速玩上 Minecraft?本教程为你详细讲解 PCL2 下载安装、整合包导入与 Mod 安装方法,并附带常见问题解决方案。PCL2 启动器拥有国内高速下载源、一键整合包导入、拖拽式 Mod 安装等功能,是目前最稳定高效的 Minec…