<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>后端 on Refrain</title><link>https://refrain-blog.pages.dev/tags/%E5%90%8E%E7%AB%AF/</link><description>Recent content in 后端 on Refrain</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Fri, 09 Oct 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://refrain-blog.pages.dev/tags/%E5%90%8E%E7%AB%AF/index.xml" rel="self" type="application/rss+xml"/><item><title>从 Python 基础到 FastAPI：一步步搭出可靠的后端 API</title><link>https://refrain-blog.pages.dev/posts/python-to-fastapi-backend-learning-path/</link><pubDate>Fri, 09 Oct 2026 00:00:00 +0000</pubDate><guid>https://refrain-blog.pages.dev/posts/python-to-fastapi-backend-learning-path/</guid><description>&lt;p&gt;第一次接触 FastAPI，几行代码就能做出一个接口。但真正的后端服务还要回答更多问题：请求数据不对怎么办？数据怎样存进数据库？用户如何登录？接口怎样测试？应用怎样安全地部署？&lt;/p&gt;
&lt;p&gt;把这些内容按顺序学，会比一上来复制一个完整项目更容易理解。本文从 Python 基础开始，沿着“接收请求、验证数据、处理业务、保存数据、测试、部署”的路线，介绍搭建后端 API 时需要掌握的知识。&lt;/p&gt;
&lt;h2 id="先补够-python-基础"&gt;先补够 Python 基础&lt;/h2&gt;
&lt;p&gt;如果这是你第一次写 Python，先熟悉列表、字典、循环、条件判断、函数和异常处理。FastAPI 的接口经常接收和返回列表、字典，也会用函数参数表达请求数据。&lt;/p&gt;
&lt;p&gt;例如，下面的列表推导式会从一组书籍中筛出指定作者的书：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;books &lt;span style="color:#fe8019"&gt;=&lt;/span&gt; [
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#b8bb26"&gt;&amp;#34;title&amp;#34;&lt;/span&gt;: &lt;span style="color:#b8bb26"&gt;&amp;#34;海边的卡夫卡&amp;#34;&lt;/span&gt;, &lt;span style="color:#b8bb26"&gt;&amp;#34;author&amp;#34;&lt;/span&gt;: &lt;span style="color:#b8bb26"&gt;&amp;#34;村上春树&amp;#34;&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#b8bb26"&gt;&amp;#34;title&amp;#34;&lt;/span&gt;: &lt;span style="color:#b8bb26"&gt;&amp;#34;挪威的森林&amp;#34;&lt;/span&gt;, &lt;span style="color:#b8bb26"&gt;&amp;#34;author&amp;#34;&lt;/span&gt;: &lt;span style="color:#b8bb26"&gt;&amp;#34;村上春树&amp;#34;&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&lt;span style="color:#b8bb26"&gt;&amp;#34;title&amp;#34;&lt;/span&gt;: &lt;span style="color:#b8bb26"&gt;&amp;#34;活着&amp;#34;&lt;/span&gt;, &lt;span style="color:#b8bb26"&gt;&amp;#34;author&amp;#34;&lt;/span&gt;: &lt;span style="color:#b8bb26"&gt;&amp;#34;余华&amp;#34;&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;author &lt;span style="color:#fe8019"&gt;=&lt;/span&gt; &lt;span style="color:#b8bb26"&gt;&amp;#34;余华&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;matches &lt;span style="color:#fe8019"&gt;=&lt;/span&gt; [book &lt;span style="color:#fe8019"&gt;for&lt;/span&gt; book &lt;span style="color:#fe8019"&gt;in&lt;/span&gt; books &lt;span style="color:#fe8019"&gt;if&lt;/span&gt; book[&lt;span style="color:#b8bb26"&gt;&amp;#34;author&amp;#34;&lt;/span&gt;] &lt;span style="color:#fe8019"&gt;==&lt;/span&gt; author]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果这段代码还看不懂，就先练习“遍历每一项、判断条件、把符合条件的项收集起来”。理解这些基础后，阅读 API 代码会轻松很多。&lt;/p&gt;
&lt;h2 id="按功能递进学习"&gt;按功能递进学习&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;阶段&lt;/th&gt;
&lt;th&gt;学习内容&lt;/th&gt;
&lt;th&gt;要达到的目标&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1. Python 基础&lt;/td&gt;
&lt;td&gt;数据类型、循环、函数、异常、对象&lt;/td&gt;
&lt;td&gt;能读懂接口里的数据处理代码&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. FastAPI 入门&lt;/td&gt;
&lt;td&gt;应用启动、路由、路径参数、查询参数&lt;/td&gt;
&lt;td&gt;能接收请求并返回 JSON&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. 请求和验证&lt;/td&gt;
&lt;td&gt;HTTP 方法、状态码、Pydantic 模型、错误响应&lt;/td&gt;
&lt;td&gt;能检查输入并给调用者清楚的结果&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4. 数据库&lt;/td&gt;
&lt;td&gt;SQL、SQLAlchemy 或 SQLModel、会话、关系、迁移&lt;/td&gt;
&lt;td&gt;重启服务后数据仍然存在&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5. 安全和可靠性&lt;/td&gt;
&lt;td&gt;密码哈希、登录、JWT、权限、日志、中间件&lt;/td&gt;
&lt;td&gt;保护接口并定位运行问题&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6. 实际功能&lt;/td&gt;
&lt;td&gt;文件、邮件、后台任务、WebSocket&lt;/td&gt;
&lt;td&gt;为应用增加常见的后端能力&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7. 测试和部署&lt;/td&gt;
&lt;td&gt;API 测试、Docker、环境变量、反向代理、HTTPS&lt;/td&gt;
&lt;td&gt;能验证并运行一个完整服务&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;每学完一项，就用一个小功能把它串起来。比如书籍 API 可以先返回固定数据，再增加请求验证，然后接数据库和登录权限，最后补测试和部署。&lt;/p&gt;
&lt;h2 id="从最小接口理解-fastapi"&gt;从最小接口理解 FastAPI&lt;/h2&gt;
&lt;p&gt;FastAPI 会根据函数签名识别路径参数、查询参数和请求体，也会利用类型信息进行验证并生成 API 文档：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#ebdbb2;background-color:#282828;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fe8019"&gt;from&lt;/span&gt; fastapi &lt;span style="color:#fe8019"&gt;import&lt;/span&gt; FastAPI
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fe8019"&gt;from&lt;/span&gt; pydantic &lt;span style="color:#fe8019"&gt;import&lt;/span&gt; BaseModel, Field
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;app &lt;span style="color:#fe8019"&gt;=&lt;/span&gt; FastAPI()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fe8019"&gt;class&lt;/span&gt; BookCreate(BaseModel):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; title: &lt;span style="color:#fabd2f"&gt;str&lt;/span&gt; &lt;span style="color:#fe8019"&gt;=&lt;/span&gt; Field(min_length&lt;span style="color:#fe8019"&gt;=&lt;/span&gt;&lt;span style="color:#d3869b"&gt;1&lt;/span&gt;, max_length&lt;span style="color:#fe8019"&gt;=&lt;/span&gt;&lt;span style="color:#d3869b"&gt;120&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; author: &lt;span style="color:#fabd2f"&gt;str&lt;/span&gt; &lt;span style="color:#fe8019"&gt;=&lt;/span&gt; Field(min_length&lt;span style="color:#fe8019"&gt;=&lt;/span&gt;&lt;span style="color:#d3869b"&gt;1&lt;/span&gt;, max_length&lt;span style="color:#fe8019"&gt;=&lt;/span&gt;&lt;span style="color:#d3869b"&gt;80&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@app.post(&lt;span style="color:#b8bb26"&gt;&amp;#34;/books&amp;#34;&lt;/span&gt;, status_code&lt;span style="color:#fe8019"&gt;=&lt;/span&gt;&lt;span style="color:#d3869b"&gt;201&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fe8019"&gt;async&lt;/span&gt; &lt;span style="color:#fe8019"&gt;def&lt;/span&gt; &lt;span style="color:#fabd2f"&gt;create_book&lt;/span&gt;(book: BookCreate):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fe8019"&gt;return&lt;/span&gt; book&lt;span style="color:#fe8019"&gt;.&lt;/span&gt;model_dump()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@app.get(&lt;span style="color:#b8bb26"&gt;&amp;#34;/books/&lt;/span&gt;&lt;span style="color:#b8bb26"&gt;{book_id}&lt;/span&gt;&lt;span style="color:#b8bb26"&gt;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#fe8019"&gt;async&lt;/span&gt; &lt;span style="color:#fe8019"&gt;def&lt;/span&gt; &lt;span style="color:#fabd2f"&gt;get_book&lt;/span&gt;(book_id: &lt;span style="color:#fabd2f"&gt;int&lt;/span&gt;, include_summary: &lt;span style="color:#fabd2f"&gt;bool&lt;/span&gt; &lt;span style="color:#fe8019"&gt;=&lt;/span&gt; &lt;span style="color:#fe8019"&gt;False&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#fe8019"&gt;return&lt;/span&gt; {&lt;span style="color:#b8bb26"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;: book_id, &lt;span style="color:#b8bb26"&gt;&amp;#34;include_summary&amp;#34;&lt;/span&gt;: include_summary}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;第一个路由接收 JSON 请求体，&lt;code&gt;BookCreate&lt;/code&gt; 规定书名和作者的格式；第二个路由从 URL 读取整数路径参数，也可以读取可选的查询参数。这里为了演示没有保存数据，生产项目需要把业务数据交给数据库。&lt;/p&gt;
&lt;p&gt;理解一个接口时，可以按这条链路往下看：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;路由根据 URL 和 HTTP 方法匹配处理函数。&lt;/li&gt;
&lt;li&gt;FastAPI 解析路径、查询参数和请求体。&lt;/li&gt;
&lt;li&gt;Pydantic 模型检查数据格式，不符合时返回验证错误。&lt;/li&gt;
&lt;li&gt;处理函数调用业务逻辑和数据库操作。&lt;/li&gt;
&lt;li&gt;FastAPI 将结果序列化为响应，并返回状态码和响应头。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;路径参数适合标识资源，例如 &lt;code&gt;/books/42&lt;/code&gt;；查询参数适合筛选或控制结果，例如 &lt;code&gt;/books?author=余华&lt;/code&gt;。创建资源通常用 &lt;code&gt;POST&lt;/code&gt;，读取用 &lt;code&gt;GET&lt;/code&gt;，更新用 &lt;code&gt;PUT&lt;/code&gt; 或 &lt;code&gt;PATCH&lt;/code&gt;，删除用 &lt;code&gt;DELETE&lt;/code&gt;。状态码也要表达清楚：成功创建常用 &lt;code&gt;201&lt;/code&gt;，找不到资源用 &lt;code&gt;404&lt;/code&gt;，输入无效则返回相应的客户端错误。&lt;/p&gt;
&lt;h2 id="从固定数据走到数据库"&gt;从固定数据走到数据库&lt;/h2&gt;
&lt;p&gt;内存中的列表或字典适合教学，但服务重启后数据会消失。接下来需要学习 SQL、数据库表、CRUD 操作和事务，再把数据保存到数据库。&lt;/p&gt;
&lt;p&gt;SQLAlchemy 提供成熟的 ORM 和数据库会话管理；SQLModel 将类型模型、数据验证与 SQLAlchemy 的数据库映射结合起来，能减少部分重复定义。无论选哪种，都要理解数据库会话的生命周期、提交和回滚，以及如何用 Alembic 管理结构迁移。&lt;/p&gt;
&lt;p&gt;随后可以学习表关系和关联查询。以书店为例，一本书可能有多个分类，一个用户可能创建多笔订单。先把实体关系画清楚，再设计表结构和 API，可以避免后续数据模型难以维护。&lt;/p&gt;
&lt;p&gt;FastAPI 的依赖注入适合统一提供数据库会话、当前用户和配置。路由负责接收和返回请求，业务逻辑放在合适的函数或服务层，数据访问也可以独立组织。小练习可以从单文件开始，项目变大后再拆分模块。&lt;/p&gt;
&lt;h2 id="异步错误和用户认证"&gt;异步、错误和用户认证&lt;/h2&gt;
&lt;p&gt;Web 服务常常要等待数据库、文件或其他接口。&lt;code&gt;async def&lt;/code&gt; 和 &lt;code&gt;await&lt;/code&gt; 能帮助程序在等待 I/O 时处理其他请求；它们不会自动加速 CPU 密集型计算。异步函数里如果调用会长时间阻塞的同步操作，仍可能拖慢其他请求。&lt;/p&gt;
&lt;p&gt;异常处理要让调用方得到合适的 HTTP 状态码和错误信息，也要避免把调试堆栈或内部机密直接返回给用户。日志可以记录请求、异常和关键业务过程，但不要把密码、令牌等敏感值写进日志。&lt;/p&gt;
&lt;p&gt;认证和授权是两个概念：认证回答“你是谁”，授权回答“你能做什么”。学习密码哈希、登录流程、JWT 和权限依赖时，应避免明文存储密码，并在每个受保护的接口确认当前用户是否有权操作资源。Pydantic 验证输入格式，不等于身份认证或业务授权。&lt;/p&gt;
&lt;p&gt;跨域资源共享（CORS）也不是登录保护。CORS 控制浏览器页面能否读取其他来源的响应；它不能替代认证、授权、输入校验或服务端访问控制。&lt;/p&gt;
&lt;h2 id="再添加真实应用功能"&gt;再添加真实应用功能&lt;/h2&gt;
&lt;p&gt;基础 API 和数据库稳定后，可以按项目需要逐项加入文件上传、邮件发送、后台任务和 WebSocket：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;文件上传&lt;/strong&gt;：检查文件大小和允许的类型，并决定文件放在对象存储还是服务器磁盘。不要仅凭用户提供的文件名判断安全性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;邮件发送&lt;/strong&gt;：把 SMTP 地址、账号和密码放在环境变量中，用邮件验证码或重置密码流程练习。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;后台任务&lt;/strong&gt;：适合发送通知、处理小型耗时工作。可靠的长任务和定时任务通常还需要队列、重试和监控。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WebSocket&lt;/strong&gt;：适合聊天和实时通知。要考虑连接鉴权、断线重连和多实例之间的消息同步。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;中间件&lt;/strong&gt;：可用于请求日志、耗时统计和跨域策略；每加一层，都要确认它会怎样影响请求和响应。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;先做一个最小版本，再处理失败、重复请求和并发等边界情况。功能不是越多越好，能说明每个模块解决什么问题更重要。&lt;/p&gt;
&lt;h2 id="测试和部署是学习的一部分"&gt;测试和部署是学习的一部分&lt;/h2&gt;
&lt;p&gt;API 测试要覆盖成功请求、验证失败、未登录访问、没有权限和资源不存在等情况。涉及数据库时，应准备可重复的测试数据，并确保测试不会误操作线上数据库。&lt;/p&gt;
&lt;p&gt;部署前，先区分开发和生产配置。开发时可以用自动重载；生产环境要妥善设置密钥、数据库连接、CORS 和日志。Docker 能把运行环境打包，反向代理可以处理 HTTPS 和请求转发，GitHub Actions 等 CI/CD 工具可以自动执行检查和发布。&lt;/p&gt;
&lt;p&gt;秘密值应通过环境变量或受控的密钥管理传入，避免提交到 Git 仓库。即使仓库是私有的，也不要把真实密码、令牌或生产密钥放进版本历史。&lt;/p&gt;
&lt;h2 id="一个适合练习的项目路线"&gt;一个适合练习的项目路线&lt;/h2&gt;
&lt;p&gt;可以从简单的书籍 API 开始，按下面的顺序迭代：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;使用内存数据实现查询和新增接口。&lt;/li&gt;
&lt;li&gt;定义 Pydantic 请求模型，加入字段校验和错误处理。&lt;/li&gt;
&lt;li&gt;接入数据库，完成创建、查询、修改和删除。&lt;/li&gt;
&lt;li&gt;增加用户注册、登录和权限检查。&lt;/li&gt;
&lt;li&gt;为关键路由和数据库逻辑编写测试。&lt;/li&gt;
&lt;li&gt;使用 Docker 部署，配置环境变量、迁移、日志和健康检查。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;每一步都可以运行、观察、修改，再继续下一步。遇到问题时，先看请求数据、响应状态和日志；不要只复制一段“能跑”的配置，却不知道它为什么有效。&lt;/p&gt;
&lt;p&gt;当你能解释请求从进入路由到写入数据库、再返回响应的过程，能用测试重现错误，也能把服务部署到一个干净环境里，这条学习路线就已经完成了最重要的部分。&lt;/p&gt;
&lt;h2 id="官方资料"&gt;官方资料&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.python.org/3/tutorial/"&gt;Python 教程&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://fastapi.tiangolo.com/tutorial/"&gt;FastAPI 官方教程&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.pydantic.dev/latest/"&gt;Pydantic 文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sqlmodel.tiangolo.com/tutorial/"&gt;SQLModel 教程&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>