跳到正文
Joeplover
学习笔记·2026-06-30·约 4 分钟阅读

FastAPI 学习笔记:从零搭建分层架构 Demo + 配置 Bug 修复实录

使用 FastAPI + 异步 SQLAlchemy + Pydantic v2 搭建了一个完整的分层架构学习项目,涵盖配置层、数据库层、数据模型、业务逻辑、路由层、依赖注入和测试。顺便还修了一个 Hermes 配置文件的 BOM 隐藏 bug。

FastAPI layered architecture with code on screen

前言

这两天主要做了两件事:搭建了一个 FastAPI 分层架构的 Demo 项目来系统学习后端开发,以及修复了一个隐藏的配置文件 BOM 问题。记下来方便以后回顾。


一、FastAPI 分层架构 Demo

之前一直在学 Spring Boot,但 Python 后端的 FastAPI 也是面试和实战中的热门技术栈。正好结合手头的学习需求和 JD 要求(FastAPI/Django/Flask 至少掌握一种),决定从零搭建一个完整的分层架构 Demo。

项目结构

整个项目按职责分层,目录用中文命名,方便直接看出每一层的用途:

FastAPI学习Demo/
├── 启动入口/          # 应用入口,中间件、生命周期、路由注册
├── 配置/              # 全局配置(pydantic-settings)
├── 数据库/            # 异步 SQLAlchemy 引擎、会话工厂
├── 数据模型/          # ORM 表模型 + Pydantic 请求/响应模型
├── 业务逻辑/          # 用户服务、商品服务(Service 层)
├── 路由层/            # API 路由定义
├── 依赖项/            # 依赖注入(DB 会话、分页、JWT 认证)
├── 测试/              # pytest + httpx 异步测试
└── requirements.txt

技术选型

组件选择理由
Web 框架FastAPI异步原生、自动生成 OpenAPI 文档、类型安全
ORMSQLAlchemy 2.x (异步)业界标准,支持 async/await
数据库SQLite (测试用内存) / PostgreSQL (生产)开发轻量,测试隔离
认证JWT (python-jose)无状态,RESTful 规范
密码哈希pbkdf2_hmac (标准库)零依赖,避开 passlib+bcrypt 兼容坑
测试pytest + httpxFastAPI 官方推荐方案

遇到的坑与解决

坑 1:passlib + bcrypt 版本不兼容

最开始用 passlib 的 CryptContext 做密码哈希,结果 pip 安装后报错:

ValueError: password cannot be longer than 72 bytes
Unable to read bcrypt version

查了一下是 passlib 1.7.4 与 bcrypt 4.0+ 不兼容的老问题。解决方式:改用 Python 标准库 hashlib.pbkdf2_hmac,SHA-256 + 随机盐 + 10 万次迭代,安全级别相当且零外部依赖。

坑 2:路由路径参数不能含中文

FastAPI 路由模板 /{商品ID} 不会匹配中文 URL 路径,所有非 ASCII 参数都会返回 404。最终将路径参数全部改为英文 {item_id},在注释中保留中文说明。

坑 3:Pydantic v2 语法变更

Pydantic v2 弃用了 class Config 语法,改用 model_config = ConfigDict(from_attributes=True)。如果不注意会报 TypeError: Config is not supported in v2。

测试结果

11 个测试用例全部通过:

  • 用户注册/登录/JWT 令牌验证
  • 获取当前用户信息
  • 商品 CRUD(创建、列表、详情、更新、删除)
  • 分页查询
  • 认证拦截(未登录访问受保护接口 → 401)
pytest 测试/测试接口.py -v  →  11/11 passed

项目地址

F:\GitHub_project\FastAPI学习Demo\


二、Hermes 配置文件 BOM 修复

在配置 Hermes Agent 时遇到了一个奇怪的错误:

Failed to parse Hermes config as YAML: 
deserializing from YAML containing more than one document is not supported

检查 config.yaml 文件内容并没有 --- 文档分隔符,YAML 结构完全正确。用 Python 的 yaml 库解析也没问题。

问题出在:Windows 的某个编辑器在保存文件时自动加上了 UTF-8 BOM(Byte Order Mark,\xEF\xBB\xBF),这 3 个字节在文件开头。Hermes 底层用的 serde_yaml(Rust 实现)对 BOM 的处理和 Python 的 yaml 库不同——它把 BOM 当成了文档前的垃圾内容,触发了 "多文档 YAML" 的错误检测。

修复方法:用二进制模式读取文件,去掉前 3 个 BOM 字节后重新写入即可。

with open(path, 'rb') as f:
    raw = f.read()
if raw.startswith(b'\xef\xbb\xbf'):
    raw = raw[len(bom):]
    with open(path, 'wb') as f:
        f.write(raw)

文件从 9634 字节变回 9631 字节,重启后错误消失。


小结

  • FastAPI 的分层架构和 Spring Boot 在思路上非常相似(Controller → Service → Repository),但异步模式和 Python 的依赖注入机制更有 Pythonic 的味道。
  • 配置文件的 BOM 问题虽然是个小坑,但不仔细排查很容易被误导——错误信息说的 "多文档" 和实际文件内容完全不匹配,只有从 YAML 解析器的底层行为去理解才能找到根本原因。
  • 测试驱动开发(先写测试,再写实现)在这个项目里帮了大忙,每次修改后运行 pytest 就能立刻知道有没有引入回归问题。