小白python入门 - 40. Web 服务与 FastAPI 入门

小白python入门 - 40. Web 服务与 FastAPI 入门 1. 本课定位是什么、为何重要上一阶段你已经会当「客户端」用 requests / httpx 去调别人的 HTTP 接口会看状态码、会设超时、会读 JSON。那套能力解决的是「我去找别人拿数据」。可是真实后端岗位的核心产出往往是反过来的——别人浏览器、App、别的服务来找你拿数据。如果只会写「跑完就退出」的脚本就没法把业务能力变成可联调、可部署的接口。所以本课先完成角色切换你要启动一个常驻进程监听本机端口接收请求返回 JSON。技术栈选 FastAPI Uvicorn前者用函数和类型注解声明路由后者负责真正监听端口并调用你的应用。学完你应能本地起服务、用浏览器 /docs 或 curl 验证并为后续书签 API 主线打底。阶段 B 你是客户端本阶段起你是服务端。概念一句话Web 服务 / API用 HTTP 把业务能力暴露给浏览器、App、其它程序FastAPI用 Python 函数 类型注解声明路由自动校验与 OpenAPI 文档UvicornASGI 服务器监听端口把网络字节流变成「调用你的 app」ASGI异步网关接口约定知道「炉灶与菜谱之间有标准」即可为何重要不会起服务就无法把路由、模型、数据库、鉴权串成产品。对比已学已学阶段 B本课阶段 C发出请求、解析响应接收请求、构造响应关心对方 URL/状态码自己决定路径、状态码、Body超时、重试在客户端进程要常驻、端口要监听调外部演示站别人或未来的你来调你生活类比角色像什么客户端脚本你去餐厅点菜、等上菜Web 服务你开餐厅听点单、出菜、报状态FastAPI菜单与出菜流程路由逻辑Uvicorn店面开门营业进程监听贯穿业务书签 API本课先健康检查与问候后续课逐步加路由、模型、配置、落库。2. 本质一次 HTTP 交换里你站哪边很多人一听「写后端」就想到 Socket、多线程、协议细节结果迟迟不敢动手。其实入门阶段你要抓住的本质很简单一次 HTTP 交换里你的进程站在服务器一侧——读方法/路径/头/体写状态码/头/体。框架已经把监听和协议解析包好了你主要写「路径对应哪个函数、返回什么 JSON」。上一节把角色切换说清了这一节用一张请求往返图和三层分工表把「菜谱 / 炉灶 / 接口约定」钉牢。地图清楚后最小应用代码才不会变成照抄咒语。浏览器 / 脚本 / 前端 你的 Uvicorn FastAPI | ---- GET /health ---- | | --- 200 {status:ok} |层像什么本课角色FastAPI 应用菜谱路径与逻辑你写的appUvicorn炉灶跑起来命令行启动ASGI炉灶与菜谱的接口约定知道有即可本质一句话服务端 常驻进程 路由函数 HTTP 响应。3. 约束与常见坑理解了「站在服务端」之后必须立刻补边界进程要一直跑、端口会冲突、本机地址不等于公网可达、改代码不生效通常是没热重载或改错文件。这些坑在课堂演示里几乎必现先列出来能省半小时抓狂。这一节用清单和对照表把红线画清。目的不是吓人而是让你第一次uvicorn失败时知道该查哪一类问题而不是怀疑「FastAPI 是不是坏了」。约束进程要一直跑着关掉终端服务就停与「跑完就退出」的脚本不同。端口只能被一个进程占用冲突就换端口。默认只给本机访问127.0.0.1更安全绑定0.0.0.0才对外网卡开放。开发用--reload生产不要依赖热重载当部署方案。返回的dict会变成 JSON不能直接返回任意不可序列化对象裸datetime等需配置或转换。常见坑坑现象正确直觉把 FastAPI 当「还要自己写 socket」无从下手框架已封装监听你写路由函数即可改代码不生效仍是旧逻辑加--reload或确认改的是正在运行的文件Address already in use起不来换--port或关掉占用进程只开了服务、不去请求「没反应」用浏览器/curl//docs主动访问外网朋友访问不了本机127.0.0.1连不上本地开发本就如此部署是后面的课把main:app写成文件名乱猜导入失败模块路径 变量名app4. 最小应用定义与创建坑讲完开始动手认最小闭环创建FastAPI实例、用装饰器挂 GET 路由、返回 dict。这三步对应「有应用、有路径、有响应」。你会看到装饰器在导入模块时就完成路由注册——不是「调用函数时才注册」。理解这一点后面拆文件、include_router时才不会疑惑「为什么 import 一下路由就生效了」。fromfastapiimportFastAPI appFastAPI(titleBookmark API,version0.1.0)app.get(/)defroot():return{message:hello bookmark api}app.get(/health)defhealth():return{status:ok}写法含义app FastAPI(...)创建应用实例Uvicorn 要加载它app.get(/health)注册GET/healthreturn dict自动 JSON 序列化默认状态码200关键语义装饰器在导入模块时完成路由注册。预期输出形态访问/health{status:ok}5. 运行方式对照写好app还不等于服务在跑——还需要 Uvicorn 加载它。main:app这种写法初学者常读错左边是模块右边是变量名中间冒号不是文件扩展名。这一节把开发命令、包路径写法、文档入口放进对照表并说明/docs、/redoc、/openapi.json各自干什么。你会发现框架根据路由自动生成 OpenAPI文档页只是它的可视化。方式命令直觉何时用开发uvicorn main:app --reload --host 127.0.0.1 --port 8000本课默认指定模块路径uvicorn app.main:app包结构项目生产倾向多进程/容器 无 reload后续部署课上线main:app读作模块main里的变量app。文档入口用途/docsSwagger UI可点按钮试调/redoc更偏阅读的文档页/openapi.json机器可读契约后续课展开参数含义--reload代码变更自动重启仅开发--host 127.0.0.1只监听本机回环--port 8000端口号冲突则改6. 小步示例查询参数预览严格的 Query 系统化在下一课但本课若完全不碰「带参数的接口」体验会偏干。这里用最小/hello?name让你看见函数参数可以来自查询串FastAPI 会帮你填。把它当作预告不要求一次吃透校验与 422。重点是服务端同样在「约定 URL 形状」客户端拼?namealice就能对上。app.get(/hello)defhello(name:strworld):return{greeting:fhello,{name}}请求响应要点GET /hello{greeting:hello, world}GET /hello?namealice{greeting:hello, alice}7. 落地场景书签服务从哪起步贯穿业务是书签 API但第一课不必上 CRUD。先定「服务活着」和「能问候」两个最小能力运维探活与前端联调都用得上。这一节用表格把场景和接口直觉对齐避免一上来就设计大而全的资源树。正确节奏是先能起、能验、能改代码热更新再加资源路径。场景最小接口直觉运维探活GET /health→{status:ok}给前端的问候GET /hello?namealice书签服务雏形本课先健康检查第 41 课起加资源路径自测文档打开/docsTry it out8. 修改前 / 修改后客户端思维 vs 服务端思维学过 requests 的人容易把「写服务」也想成「我再发一次请求」——方向反了。用对照表把思维拧过来你不再拼对方 URL而是定义自己的路径不再解析对方 JSON而是构造自己的 JSON。这种对照会反复出现在后面几课路径参数、请求体、依赖注入都是在服务端兑现「对外约定」。维度修改前客户端修改后服务端主动方你发起别人发起你响应进程短命脚本常驻监听成功标志对方 200你返回 200 与约定字段调试入口打日志看响应/docs curl 双验证失败常见超时、DNS端口占用、路由未注册9. 环境与目录建议工具链没摆好后面所有课都会卡在「包找不到 / 命令不对」。这一节固定虚拟环境、依赖版本下限、Windows 下如何跑cat EOF类脚本。Windows 用户推荐 Cygwin 或 WSL 执行带 heredoc 的 bash 片段PowerShell 也可手建文件但课程示例统一按 bash 写法给出便于复制。项目要求Python3.10推荐 3.12包fastapi、uvicorn[standard]Windows推荐 Cygwin / WSL跑cat EOF脚本或 VS Code 终端手建文件mkdir-p~/python-lab/src/day40cd~/python-lab/src/day40 python3-mvenv .venvsource.venv/bin/activate# Windows PowerShell: .\.venv\Scripts\Activate.ps1pipinstallfastapi0.110uvicorn[standard]0.2710. 综合实践完整可运行脚本前面是分块概念这一节一次落地写入main.py、启动 Uvicorn、另开终端验证。请完整跑通不要只看不敲——「服务起来了」的体感建立不起来后面路由课会虚。Windows 请在 Cygwin/WSL 中执行 heredoc若必须用 PowerShell可手动创建同名文件并粘贴 EOF 之间的内容。服务占用前台终端时验证命令请开第二个终端。mkdir-p~/python-lab/src/day40cd~/python-lab/src/day40# 已激活 venv 并安装依赖后catmain.pyEOF from fastapi import FastAPI app FastAPI(titleDay40 Bookmark API, version0.1.0) app.get(/) def root(): return {message: hello bookmark api, course: 40} app.get(/health) def health(): return {status: ok} app.get(/hello) def hello(name: str world): return {greeting: fhello, {name}} EOFuvicorn main:app--reload--host127.0.0.1--port8000另开终端验证curl-shttp://127.0.0.1:8000/healthcurl-shttp://127.0.0.1:8000/hello?namealicecurl-shttp://127.0.0.1:8000/浏览器打开http://127.0.0.1:8000/docs→ 选接口 →Try it out→Execute。预期输出{status:ok} {greeting:hello, alice} {message:hello bookmark api,course:40}检查项通过标准健康检查Body 含status:ok问候name进入 greeting文档/docs能看到三条 GET热重载改message字符串后刷新仍更新保存后等一秒11. 常见问答课堂高频问题集中在FastAPI 和 Flask 差在哪、Uvicorn 能不能省略、为什么必须另开终端、main:app报错怎么办。集中答疑减少「概念都懂了但命令跑不通」的挫败感。QFastAPI 和 Flask 入门差在哪AFastAPI 强调类型注解、自动校验与 OpenAPI本系列统一 FastAPI不强制对比深度。Q能不用 Uvicorn 吗A开发期几乎总要 ASGI 服务器Uvicorn 是官方推荐默认之一。Q为什么 curl 要另开终端A前台跑着的 Uvicorn 占住了当前 shell不停服务就另开窗口发请求。QCould not import module mainA当前目录是否有main.py是否在项目目录执行包结构时用app.main:app。Q返回中文乱码A终端编码与 JSON 本身 UTF-8浏览器/docs一般正常。确保源文件 UTF-8 保存。12. 错误示范对照专辟对照把「假服务端」和「真最小服务」并排看。常见错误包括写了函数却没装饰器、return 了不可序列化对象、host/port 乱绑导致自己都访问不了。错误写法问题正确直觉定义了def health()无装饰器路由未注册app.get(/health)return open(x)无法 JSON 化返回 dict/list/模型只print不 return客户端拿到 null/空明确 return 响应体绑定错误端口却 curl 8000连接失败命令与 curl 端口一致# 修改前有函数无路由defhealth():return{status:ok}# 修改后app.get(/health)defhealth():return{status:ok}13. 自我检查清单学完先别急着翻第 41 课。用清单打勾角色切换、三层分工、最小代码、启动命令、curl 与 /docs 双验证。勾不上的回到对应小节五分钟比往前赶更有效。能用一句话说清客户端 vs 服务端能说出 FastAPI 与 Uvicorn 各干什么会写GET /与GET /health会uvicorn main:app --reload并成功访问会用/docsTry it out会用 curl 验证 JSON知道端口占用时如何处理14. 与后续课的衔接地图本课只搭舞台。后面书签 API 会按「路径 → 请求体 → 依赖配置 → 数据库」加厚。知道地图才不会觉得每课在换题材。课你将加上41路径/查询参数、状态码、APIRouter、内存书签读删42Pydantic 模型、POST/PATCH Body43Depends、Settings、.env44SQLAlchemy SQLite 持久化 CRUD15. 客户端调自己的服务闭环阶段 B 你会用 requests 调别人现在服务在本机完全可以用同一套客户端能力调自己形成「一端写服务、一端写调用」的闭环。这对以后写集成测试、健康检查脚本也很有用。服务仍要用 Uvicorn 先跑着下面脚本在另一个终端执行。超时建议带上避免服务没起时一直挂起。importrequests basehttp://127.0.0.1:8000rrequests.get(f{base}/health,timeout5)print(r.status_code,r.json())r2requests.get(f{base}/hello,params{name:lab},timeout5)print(r2.json())预期输出形态200 {status: ok} {greeting: hello, lab}方式适合浏览器/docs探索、演示curl终端快速验requests/httpx脚本化、后续测试总结到了收束的时候。若整课只能带走几句角色已从「调别人」换成「被别人调」FastAPI 写 appUvicorn 跑 appdict 变 JSON用 /docs 和 curl 双验证进程常驻、端口唯一、本机开发先绑回环地址。这些句子后面每课都会用到。先保证「能起、能调、能改」再谈漂亮架构。服务端 常驻进程 路由函数 HTTP 响应。FastAPI 声明路由与文档Uvicorn 负责监听与调用 app。main:app 模块里的应用实例开发加--reload。return dict→ JSON默认 200用/docs与 curl 验证。端口冲突换端口本地127.0.0.1不等于公网可达。贯穿业务从书签 API 健康检查起步后续课逐步加厚。小练笔练习用来自测不要求一次全对更不要先翻答案。题型覆盖选择、判断、简答与可选实践建议你真的改一行返回字段保存后看热重载是否生效。做题时优先用自己的话解释「为什么」。卡很久的题回到「三层分工」和「运行方式」两节通常就能想通。题 1Uvicorn 的主要职责A. 写 SQLB. ASGI 服务器监听并调用 appC. 画前端页面题 2uvicorn main:app里的app指什么题 3判断浏览器打开/docs能试调接口说明 OpenAPI 文档由框架根据路由自动生成。题 4端口被占用时优先做什么题 5用「方法、URL、期望状态码、请求体、响应体」描述一次对/health的成功访问。题 6判断开发环境绑定127.0.0.1后公网用户一定能访问你的服务。题 7为什么服务启动后当前终端不能再直接敲很多交互命令题 8GET /hello?namebob若路由是def hello(name: str world)响应 greeting 应是什么题 9可选实践给/增加字段domain: bookmark保存后不手动重启依赖--reloadcurl 验证新字段出现。题 10一句话区分 FastAPI 与 Uvicorn。小练笔参考答案参考答案在下面。请先自己做完再看。答案只给标准方向简答题意思对即可。若你的表述和答案不同但道理成立可以算对。真正要修正的是把客户端/服务端角色搞反或以为框架还要你手写 socket 的理解。题 1B题 2main模块中FastAPI()创建的应用实例变量。题 3对题 4换端口或结束占用该端口的进程。题 5示例GEThttp://127.0.0.1:8000/health无 Body期望 200Body{status:ok}。题 6错题 7Uvicorn 前台占用该终端验证请另开终端或后台运行开发期另开更直观。题 8hello, bob即{greeting:hello, bob}。题 9以你机器为准保存后 curl/应出现domain:bookmark。题 10FastAPI 写应用与路由Uvicorn 跑 ASGI 应用并监听端口。合理即可