专为前端开发者打造的后端学习项目
这是一个从零开始的 FastAPI 后端教学项目,涵盖了后端开发的所有核心知识点。所有代码都有详细的中文注释,帮助你快速掌握 Python Web 开发。
✅ 详细注释:每个文件都有大量注释,解释"为什么"而不只是"怎么做" ✅ 完整架构:统一响应格式、错误码、异常处理、日志系统 ✅ 最佳实践:遵循工业标准的项目结构和代码规范 ✅ 前端友好:从前端视角解释后端概念,易于理解 ✅ 实战导向:可直接用于真实项目
- 统一响应格式(Response Schema)
- 错误码体系(Error Codes)
- 自定义异常处理(Custom Exceptions)
- 全局异常处理器(Global Exception Handler)
- SQLAlchemy ORM(对象关系映射)
- 异步数据库操作
- 数据库迁移(Alembic)
- 连接池管理
- 密码加密(bcrypt)
- JWT 认证
- 依赖注入(Dependency Injection)
- 权限控制
- 请求日志记录
- CORS 跨域处理
- 异常统一处理
- RESTful API 设计
- Pydantic 数据验证
- 自动生成 API 文档
- 分页、搜索、过滤(offset/limit + cursor,见
docs/pagination-guide.md) - Server-Sent Events(SSE 服务端推送)
- 邮件发送(aiosmtplib + Jinja2 模板,见
docs/email-guide.md) - 大文件分片上传(init / 分片 / 完成 / 续传,见
docs/chunked-upload-guide.md)
backend-tutorial/
├── common/ # 公共模块
│ ├── response.py # 统一响应格式 ⭐
│ ├── error_codes.py # 错误码定义 ⭐
│ └── exceptions.py # 自定义异常 ⭐
├── core/ # 核心配置
│ ├── config.py # 配置文件 ⭐
│ ├── database.py # 数据库配置 ⭐
│ ├── pagination.py # 分页助手(offset / cursor)⭐
│ └── security.py # 安全模块(密码、JWT)⭐
├── middleware/ # 中间件
│ ├── logger.py # 请求日志中间件 ⭐
│ └── error_handler.py # 全局异常处理器 ⭐
├── models/ # 数据库模型(ORM)
│ └── user.py # 用户模型 ⭐
├── schemas/ # Pydantic 模型(API 数据格式)
│ └── user.py # 用户 Schema ⭐
├── api/ # API 路由
│ ├── deps.py # 依赖注入 ⭐
│ └── v1/
│ ├── auth.py # 认证接口(注册、登录)⭐
│ ├── users.py # 用户接口 ⭐
│ ├── files.py # 文件上传 / 分享 ⭐
│ ├── chunked_uploads.py # 大文件分片上传 ⭐
│ ├── sse.py # SSE 服务端推送 ⭐
│ └── email.py # 邮件演示接口 ⭐
├── docs/
│ ├── sse-guide.md # SSE 学习指南
│ ├── pagination-guide.md # 分页学习指南 ⭐
│ ├── email-guide.md # 邮件发送学习指南 ⭐
│ └── chunked-upload-guide.md # 分片上传学习指南 ⭐
├── services/ # 业务逻辑层
│ ├── user_service.py # 用户服务 ⭐
│ ├── email_service.py # SMTP / 模板 / 附件 ⭐
│ └── chunked_upload_service.py # 分片会话 / 校验 / 拼片 ⭐
├── templates/email/ # Jinja2 邮件模板(HTML + 纯文本)
├── utils/ # 工具函数
│ └── logger.py # 日志配置 ⭐
├── logs/ # 日志文件目录
├── main.py # 应用入口 ⭐
├── requirements.txt # Python 依赖
├── .env.example # 环境变量模板
└── README.md # 项目文档(本文件)
⭐ = 包含详细注释和学习笔记的核心文件
cd backend-tutorial# Windows
python -m venv venv
venv\Scripts\activate
# Linux/macOS
python3 -m venv venv
source venv/bin/activatepip install -r requirements.txt# 复制环境变量模板
cp .env.example .env
# 编辑 .env 文件,修改配置
# 特别注意:生产环境必须修改 SECRET_KEY!python main.py或者使用 uvicorn:
uvicorn main:app --reload --host 0.0.0.0 --port 8080打开浏览器访问:
- Swagger UI: http://localhost:8080/docs
- ReDoc: http://localhost:8080/redoc
POST http://localhost:8080/api/v1/auth/register
Content-Type: application/json
{
"username": "alice",
"email": "alice@example.com",
"password": "123456"
}响应:
{
"code": 0,
"message": "注册成功",
"data": {
"id": 1,
"username": "alice",
"email": "alice@example.com",
"is_active": true,
"is_superuser": false,
"created_at": "2024-01-01T12:00:00",
"updated_at": "2024-01-01T12:00:00"
}
}POST http://localhost:8080/api/v1/auth/login
Content-Type: application/json
{
"username": "alice",
"password": "123456"
}响应:
{
"code": 0,
"message": "登录成功",
"data": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer"
}
}GET http://localhost:8080/api/v1/users?page=1&page_size=10
Authorization: Bearer <token>默认是页码分页。把上一页返回的 next_cursor 再传回去,就改成游标分页:
GET http://localhost:8080/api/v1/users?page_size=10&cursor=<next_cursor>文件列表同样支持这组参数,旧字段 files / total 仍然保留:
GET http://localhost:8080/api/v1/files/list?page=1&page_size=10详见 docs/pagination-guide.md。
GET http://localhost:8080/api/v1/users/me
Authorization: Bearer <token>响应:
{
"code": 0,
"message": "success",
"data": {
"id": 1,
"username": "alice",
"email": "alice@example.com",
...
}
}阅读文件:common/response.py
关键概念:
- 为什么需要统一响应格式?
- 成功和失败的响应结构
- 分页数据的处理
阅读文件:common/error_codes.py, common/exceptions.py
关键概念:
- HTTP 状态码 vs 业务错误码
- 如何设计错误码
- 自定义异常类
阅读文件:core/config.py, core/database.py
关键概念:
- 环境变量管理
- 数据库连接池
- ORM 基础
阅读文件:core/security.py, api/deps.py
关键概念:
- 密码加密(不可逆)
- JWT 工作原理
- 依赖注入
阅读文件:middleware/, utils/logger.py
关键概念:
- 中间件执行顺序
- 请求追踪
- 日志分级
阅读文件:models/user.py, schemas/user.py
关键概念:
- ORM 模型 vs Pydantic 模型
- 数据库字段类型
- 数据验证
阅读文件:services/, api/v1/
关键概念:
- 分层架构
- RESTful API 设计
- CRUD 操作
阅读文件:api/v1/sse.py、docs/sse-guide.md
关键概念:
- SSE vs 轮询 vs WebSocket
StreamingResponse与text/event-stream- 客户端断开和
Last-Event-ID续传
阅读文件:core/pagination.py、docs/pagination-guide.md
关键概念:
- offset/limit(页码)vs cursor(游标)
COUNT(*)的代价:表格要总数,信息流只要has_next- 增量字段兼容旧客户端(文件列表仍返回
files/total)
阅读文件:services/email_service.py、api/v1/email.py、docs/email-guide.md
关键概念:
aiosmtplib异步 SMTP(不要在 FastAPI 里用同步smtplib)- Jinja2 HTML + 纯文本 fallback
- 没配
SMTP_HOST时 dry-run;Celery 可选,Broker 挂了回退同步 - 欢迎 / 验证 / 重置是演示,不会改用户表或密码
阅读文件:services/chunked_upload_service.py、api/v1/chunked_uploads.py、docs/chunked-upload-guide.md
关键概念:
- 为什么整文件一次 POST 会超时 / 占内存 / 失败重来
- init → PUT 分片 → complete / abort(对标 S3 Multipart)
- 单片和整文件 SHA-256;同一片再传是幂等的
- 临时目录拼好后
os.replace到uploads/,不替换POST /upload
为什么需要?
- 前端可以写统一的拦截器处理响应
- 减少前端的判断逻辑
- 提高团队协作效率
响应结构:
{
"code": 0, // 0=成功,非0=失败
"message": "success", // 提示信息
"data": {} // 实际数据
}前端使用(Axios 示例):
axios.interceptors.response.use(
response => {
if (response.data.code === 0) {
return response.data.data; // 返回实际数据
} else {
// 统一错误提示
message.error(response.data.message);
return Promise.reject(response.data);
}
}
);设计规范:
0:成功4xxxx:客户端错误(用户输入、权限等)5xxxx:服务器错误(系统异常)
错误码示例:
40001: 用户名已存在
40002: 邮箱已存在
41000: 未登录
41001: Token 过期
50000: 服务器内部错误前端处理:
switch(response.data.code) {
case 41000: // 未登录
case 41001: // Token 过期
router.push('/login');
break;
case 40001: // 用户名已存在
formErrors.username = '用户名已存在';
break;
default:
message.error(response.data.message);
}登录流程:
1. 用户输入用户名和密码
2. 后端验证用户名和密码
3. 验证通过,生成 JWT Token
4. 返回 Token 给前端
5. 前端存储 Token(localStorage)
访问接口流程:
1. 前端在请求头携带 Token
Authorization: Bearer <token>
2. 后端验证 Token
3. Token 有效,返回数据
4. Token 无效/过期,返回 401 错误
安全性:
- Token 有签名,无法篡改
- 设置过期时间,降低风险
- 不要在 Token 里存敏感信息(密码等)
ORM 的好处:
- 用面向对象的方式操作数据库
- 防止 SQL 注入
- 跨数据库(SQLite、PostgreSQL、MySQL)
示例对比:
❌ 原生 SQL(不推荐):
cursor.execute("SELECT * FROM users WHERE username = ?", (username,))✅ ORM(推荐):
user = await db.execute(select(User).where(User.username == username))不使用依赖注入:
@router.get("/users/me")
async def get_me(request: Request):
token = request.headers.get("Authorization")
user_id = parse_token(token)
db = get_database()
user = db.query(User).filter(User.id == user_id).first()
return user使用依赖注入:
@router.get("/users/me")
async def get_me(current_user: User = Depends(get_current_user)):
return current_user # FastAPI 自动处理所有逻辑- 在
api/v1/创建新的路由文件 - 定义路由函数
- 在
main.py中注册路由
- 在
models/创建模型类 - 在
schemas/创建对应的 Pydantic 模型 - 运行应用,表会自动创建(或使用 Alembic 迁移)
修改 .env 文件中的 ACCESS_TOKEN_EXPIRE_MINUTES
- 修改
.env文件(DEBUG=False, 修改 SECRET_KEY) - 使用 PostgreSQL 替代 SQLite
- 使用 Gunicorn + Uvicorn Workers
- 配置 Nginx 反向代理
以下功能你可以自己尝试实现:
- 邮件发送演示(SMTP + 模板 + 附件,见
docs/email-guide.md) - 完整邮箱验证(写库 / 一次性 token)
- 完整忘记密码(校验 token、改哈希)
- 角色和权限管理(RBAC)
- 文件上传
- 大文件分片上传(见
docs/chunked-upload-guide.md) - 分页(offset / cursor,见
docs/pagination-guide.md) - Server-Sent Events(见
docs/sse-guide.md) - Refresh Token
- 接口限流
- 数据缓存(Redis)
- 单元测试 / API 集成测试
- Docker 部署
- 类比学习:文件中有大量前端类比,帮助你理解后端概念
- 动手实践:不要只看代码,一定要自己运行和修改
- 阅读注释:每个文件的注释都很详细,慢慢读
- 调试技巧:多用
print()和日志查看数据流转
- 先运行项目,看效果
- 阅读核心文件(标记 ⭐ 的文件)
- 尝试添加新功能
- 阅读 FastAPI 官方文档
如果你有任何问题或建议,欢迎提 Issue!
祝学习愉快!🎉