目录
2.2 第一个 FastAPI 应用:Hello World
6.1 生产环境启动(Uvicorn + Gunicorn)
7.2 坑点 2:Pydantic 模型未启用 ORM 模式

class 卑微码农:
def __init__(self):
self.技能 = ['能读懂十年前祖传代码', '擅长用Ctrl+C/V搭建世界', '信奉"能跑就别动"的玄学']
self.发量 = 100 # 初始发量
self.咖啡因耐受度 = '极限'
def 修Bug(self, bug):
try:
# 试图用玄学解决问题
if bug.严重程度 == '离谱':
print("这一定是环境问题!")
else:
print("让我看看是谁又没写注释...哦,是我自己。")
except Exception as e:
# 如果try块都救不了,那就...
print("重启一下试试?")
self.发量 -= 1 # 每解决一个bug,头发-1
# 实例化一个我
我 = 卑微码农()
引言
在 Python Web 框架生态中,FastAPI 凭借 “高性能、易上手、自动生成文档” 三大核心优势异军突起,短短几年就成为开发者构建 API 的首选工具。它不仅能轻松应对高并发场景,还能通过类型提示实现自动数据验证和接口文档生成,彻底解决了传统框架 “开发慢、调试繁、文档乱” 的痛点。
本文从 FastAPI 基础概念切入,循序渐进讲解核心功能,搭配完整实战案例,从环境搭建、接口开发到部署上线,全程手把手教学,帮你快速掌握 FastAPI 的开发技巧,轻松构建高性能 API 服务。
一、为什么选 FastAPI?—— 对比传统框架的核心优势

在 FastAPI 出现之前,Python 开发者构建 API 主要依赖 Flask 和 Django:
- Flask:轻量灵活,但需要手动处理数据验证、文档编写,扩展性差,高并发场景下性能不足;
- Django:功能全面,但笨重冗余,自带的 Admin 后台、ORM 等组件并非 API 开发必需,且同步架构难以应对高并发。
而 FastAPI 完美弥补了这些短板,核心优势如下:
- 性能强悍:基于 Starlette 和 Pydantic 开发,支持异步处理,性能接近 Node.js 和 Go,远超 Flask;
- 开发高效:通过 Python 类型提示自动完成数据验证、接口文档生成,无需手动编写文档;
- 易用性强:语法简洁直观,新手可快速上手,同时支持复杂场景(依赖注入、认证授权、WebSocket 等);
- 生态完善:兼容 FastAPI、Starlette 的组件,支持多种数据库和部署方式,扩展性强。
一组简单的性能对比(处理单请求响应时间):
- Flask:约 10ms
- Django:约 15ms
- FastAPI:约 2ms
无论是开发个人项目、企业内部接口,还是高并发的生产级 API,FastAPI 都能轻松胜任。
二、基础入门:环境搭建与第一个 FastAPI 应用

2.1 环境搭建
2.1.1 安装依赖
FastAPI 的运行需要依赖uvicorn(ASGI 服务器,用于启动应用),推荐使用虚拟环境隔离依赖:
# 创建虚拟环境(Python 3.7+)
python -m venv fastapi-env
# 激活虚拟环境(Windows)
fastapi-env\Scripts\activate
# 激活虚拟环境(Linux/Mac)
source fastapi-env/bin/activate
# 安装FastAPI和uvicorn
pip install fastapi uvicorn
2.1.2 验证安装
安装完成后,运行以下命令查看版本:
pip list | grep fastapi # 输出fastapi及其版本,如fastapi 0.104.1
pip list | grep uvicorn # 输出uvicorn及其版本,如uvicorn 0.24.0
2.2 第一个 FastAPI 应用:Hello World
新建文件main.py,编写最简单的 FastAPI 应用:
# 导入FastAPI类
from fastapi import FastAPI
# 创建FastAPI应用实例
app = FastAPI()
# 定义路由:GET请求,路径为"/"
@app.get("/")
def read_root():
# 返回字典,FastAPI自动转为JSON响应
return {"message": "Hello FastAPI!"}
启动应用
在终端运行以下命令启动服务:
uvicorn main:app --reload
main:Python 文件名(main.py);app:FastAPI 实例名(app = FastAPI());--reload:开发模式,代码修改后自动重启服务(生产环境禁用)。
启动成功后,终端会输出:
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [xxxx] using WatchFiles
INFO: Started server process [xxxx]
INFO: Waiting for application startup.
INFO: Application startup complete.
访问接口
打开浏览器访问 http://127.0.0.1:8000,会看到 JSON 响应:
{"message":"Hello FastAPI!"}
自动生成的接口文档
FastAPI 最强大的特性之一是自动生成接口文档,无需手动编写:
- Swagger UI 文档:
http://127.0.0.1:8000/docs(支持在线调试); - ReDoc 文档:
http://127.0.0.1:8000/redoc(更简洁的文档展示)。
打开 Swagger UI 文档,点击Try it out即可测试接口,非常方便。
三、核心功能:API 接口开发的核心玩法

3.1 路径参数:动态匹配 URL 路径
路径参数用于从 URL 中提取动态数据,比如用户 ID、商品编号等,通过{参数名}定义。
基础示例:获取用户信息
from fastapi import FastAPI
app = FastAPI()
# 路径参数user_id,类型提示为int
@app.get("/users/{user_id}")
def get_user(user_id: int):
return {"user_id": user_id, "message": "用户信息查询成功"}
测试接口
- 访问
http://127.0.0.1:8000/users/100,返回:{"user_id":100,"message":"用户信息查询成功"}; - 若访问
http://127.0.0.1:8000/users/abc,会自动返回 422 错误:{"detail":[{"loc":["path","user_id"],"msg":"value is not a valid integer","type":"type_error.integer"}]},这就是 FastAPI 的自动数据验证功能。
路径参数约束:枚举类型
如果路径参数只能是固定值(比如性别、状态),可以使用枚举类型限制:
from fastapi import FastAPI
from enum import Enum
app = FastAPI()
# 定义枚举类
class Gender(str, Enum):
MALE = "male"
FEMALE = "female"
OTHER = "other"
# 路径参数gender必须是Gender枚举中的值
@app.get("/users/gender/{gender}")
def get_users_by_gender(gender: Gender):
return {"gender": gender.value, "count": 100}
访问 http://127.0.0.1:8000/users/gender/male,返回:{"gender":"male","count":100};若传入其他值,会自动提示合法选项。
3.2 查询参数:URL 中的键值对参数
查询参数是 URL 中?后的键值对,用于过滤、分页等场景,FastAPI 会自动识别函数中未定义为路径参数的参数作为查询参数。
基础示例:分页查询用户列表
from fastapi import FastAPI
app = FastAPI()
# 模拟用户数据
users = [
{"id": 1, "name": "张三", "age": 20},
{"id": 2, "name": "李四", "age": 25},
{"id": 3, "name": "王五", "age": 30},
{"id": 4, "name": "赵六", "age": 35},
]
# page:页码,默认1;limit:每页数量,默认2
@app.get("/users")
def get_users(page: int = 1, limit: int = 2):
# 计算切片起始和结束索引
start = (page - 1) * limit
end = start + limit
return {
"page": page,
"limit": limit,
"total": len(users),
"data": users[start:end]
}
测试接口
- 访问
http://127.0.0.1:8000/users,默认返回第 1 页,每页 2 条数据; - 访问
http://127.0.0.1:8000/users?page=2&limit=1,返回第 2 页,每页 1 条数据:json
{"page":2,"limit":1,"total":4,"data":[{"id":3,"name":"王五","age":30}]}
可选查询参数
如果查询参数可选,可以设置默认值为None:
@app.get("/users/search")
def search_users(name: str | None = None, age: int | None = None):
# 过滤用户
result = users
if name:
result = [user for user in result if name in user["name"]]
if age:
result = [user for user in result if user["age"] == age]
return {"data": result}
访问 http://127.0.0.1:8000/users/search?name=李,返回:{"data":[{"id":2,"name":"李四","age":25}]}。
3.3 请求体:接收 POST/PUT 请求的数据
请求体用于接收客户端发送的大量数据(如创建用户、更新信息),FastAPI 通过Pydantic 模型定义请求体结构,自动完成数据验证和类型转换。
步骤 1:定义 Pydantic 模型
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
# 定义请求体模型(数据验证)
class UserCreate(BaseModel):
name: str # 必选字段,字符串类型
age: int # 必选字段,整数类型
email: str | None = None # 可选字段,字符串类型,默认None
is_active: bool = True # 可选字段,布尔类型,默认True
步骤 2:编写 POST 接口
# 模拟数据库
db_users = []
@app.post("/users", status_code=201) # status_code设置响应状态码
def create_user(user: UserCreate):
# 将Pydantic模型转为字典,添加到数据库
user_dict = user.dict()
user_dict["id"] = len(db_users) + 1 # 生成自增ID
db_users.append(user_dict)
return {"message": "用户创建成功", "data": user_dict}
测试接口
打开 Swagger 文档(/docs),找到/users的 POST 接口,点击Try it out,输入请求体:
{
"name": "孙七",
"age": 28,
"email": "sunqi@example.com"
}
点击Execute,返回:
{
"message": "用户创建成功",
"data": {
"name": "孙七",
"age": 28,
"email": "sunqi@example.com",
"is_active": true,
"id": 1
}
}
若请求体不符合模型定义(如age传入字符串),会自动返回验证错误。
3.4 响应模型:规范接口返回格式
响应模型用于定义接口的返回结构,确保返回数据的一致性,同时自动过滤不需要的字段。
示例:定义用户响应模型
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
# 定义请求体模型
class UserCreate(BaseModel):
name: str
age: int
email: str | None = None
is_active: bool = True
# 定义响应模型(过滤is_active字段)
class UserResponse(BaseModel):
id: int
name: str
age: int
email: str | None = None
# 配置:允许接收额外字段(如数据库返回的其他字段)
class Config:
orm_mode = True # 支持ORM对象直接转换
# 模拟数据库
db_users = []
@app.post("/users", response_model=UserResponse, status_code=201)
def create_user(user: UserCreate):
user_dict = user.dict()
user_dict["id"] = len(db_users) + 1
db_users.append(user_dict)
return user_dict # 自动按照UserResponse格式返回,过滤is_active
测试接口后,返回结果中不会包含is_active字段,确保响应格式统一。
四、进阶功能:解锁 FastAPI 的高级玩法

4.1 依赖注入:解耦代码,提升复用性
依赖注入是 FastAPI 的核心特性之一,用于管理可复用的资源(如数据库连接、认证逻辑、日志工具),避免代码重复,提升可维护性。
示例 1:简单依赖项(复用公共逻辑)
from fastapi import FastAPI, Depends
app = FastAPI()
# 定义依赖项:获取当前时间
def get_current_time():
from datetime import datetime
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# 接口依赖get_current_time,自动注入返回值
@app.get("/hello")
def hello(current_time: str = Depends(get_current_time)):
return {"message": "Hello FastAPI!", "current_time": current_time}
访问接口,返回:{"message":"Hello FastAPI!","current_time":"2024-10-01 15:30:00"}。
示例 2:带参数的依赖项(数据库连接)
from fastapi import FastAPI, Depends
import sqlite3
app = FastAPI()
# 定义带参数的依赖项:数据库连接
def get_db(db_name: str = "test.db"):
# 建立数据库连接
conn = sqlite3.connect(db_name)
conn.row_factory = sqlite3.Row # 使查询结果可通过列名访问
try:
yield conn # 提供连接给接口使用
finally:
conn.close() # 接口执行完成后关闭连接
# 接口依赖数据库连接
@app.get("/db/users")
def get_db_users(db = Depends(get_db)):
cursor = db.cursor()
cursor.execute("SELECT * FROM users") # 假设users表已存在
users = [dict(row) for row in cursor.fetchall()]
return {"data": users}
依赖注入确保了数据库连接的统一管理,避免资源泄露。
4.2 认证授权:保护接口安全
FastAPI 支持多种认证方式,最常用的是 OAuth2 + JWT(JSON Web Token),用于保护需要登录才能访问的接口。
步骤 1:安装依赖
pip install python-jose[cryptography] passlib[bcrypt]
步骤 2:实现 JWT 认证逻辑
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jose import JWTError, jwt
from passlib.context import CryptContext
from datetime import datetime, timedelta
app = FastAPI()
# 配置项(实际项目中应放在环境变量中)
SECRET_KEY = "your-secret-key-keep-it-safe" # 密钥,用于签名JWT
ALGORITHM = "HS256" # 加密算法
ACCESS_TOKEN_EXPIRE_MINUTES = 30 # Token过期时间(30分钟)
# 密码加密上下文
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
# OAuth2密码模式
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
# 模拟用户数据库(实际项目中应连接真实数据库)
fake_users_db = {
"admin": {
"username": "admin",
"full_name": "Admin User",
"email": "admin@example.com",
"hashed_password": pwd_context.hash("admin123"), # 加密后的密码
"disabled": False,
}
}
# 验证密码
def verify_password(plain_password, hashed_password):
return pwd_context.verify(plain_password, hashed_password)
# 获取用户
def get_user(db, username: str):
if username in db:
user_dict = db[username]
return user_dict
return None
# 验证用户并生成Token
def authenticate_user(fake_db, username: str, password: str):
user = get_user(fake_db, username)
if not user:
return False
if not verify_password(password, user["hashed_password"]):
return False
return user
# 创建访问Token
def create_access_token(data: dict):
to_encode = data.copy()
# 设置过期时间
expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
to_encode.update({"exp": expire})
# 生成Token
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded_jwt
# 获取当前用户(依赖项)
async def get_current_user(token: str = Depends(oauth2_scheme)):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="无效的认证凭据",
headers={"WWW-Authenticate": "Bearer"},
)
try:
# 解码Token
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise credentials_exception
except JWTError:
raise credentials_exception
user = get_user(fake_users_db, username=username)
if user is None:
raise credentials_exception
return user
# 获取Token接口(登录接口)
@app.post("/token")
async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()):
user = authenticate_user(fake_users_db, form_data.username, form_data.password)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="用户名或密码错误",
headers={"WWW-Authenticate": "Bearer"},
)
# 生成Token,sub字段存储用户名
access_token = create_access_token(data={"sub": user["username"]})
return {"access_token": access_token, "token_type": "bearer"}
# 受保护的接口(需要登录才能访问)
@app.get("/users/me")
async def read_users_me(current_user: dict = Depends(get_current_user)):
return current_user
测试认证流程
- 访问
/docs,先调用/token接口,输入用户名admin和密码admin123,获取 Token; - 调用
/users/me接口,点击Authorize,输入Bearer + Token,即可访问接口,返回当前用户信息。
4.3 异步处理:提升高并发性能
FastAPI 原生支持异步编程,通过async/await语法编写异步接口,能高效处理 IO 密集型任务(如数据库查询、网络请求),提升系统并发能力。
示例:异步接口与异步数据库操作
from fastapi import FastAPI
import asyncio
# 假设使用异步数据库驱动(如asyncpg for PostgreSQL)
from async_fake_db import AsyncFakeDB # 模拟异步数据库
app = FastAPI()
db = AsyncFakeDB()
# 异步接口:创建用户
@app.post("/async/users")
async def create_async_user(name: str, age: int):
# 异步数据库操作(await等待操作完成)
user_id = await db.insert_user({"name": name, "age": age})
# 模拟异步IO延迟(如网络请求)
await asyncio.sleep(0.1)
return {"message": "异步创建用户成功", "user_id": user_id}
# 异步接口:查询用户
@app.get("/async/users/{user_id}")
async def get_async_user(user_id: int):
user = await db.get_user(user_id)
if not user:
return {"message": "用户不存在"}
return {"data": user}
异步接口的优势在于:当处理 IO 任务时,系统可以同时处理其他请求,而无需等待 IO 完成,大幅提升高并发场景下的吞吐量。
4.4 数据验证:Pydantic 模型的高级用法
Pydantic 模型不仅能定义数据结构,还支持复杂的数据验证规则,确保输入数据的合法性。
示例:带验证规则的用户模型
from fastapi import FastAPI
from pydantic import BaseModel, Field, EmailStr
from typing import List
app = FastAPI()
# 定义带验证规则的模型
class User(BaseModel):
# 姓名:必填,长度2-20
name: str = Field(..., min_length=2, max_length=20, description="用户姓名")
# 年龄:必填,18-60岁
age: int = Field(..., ge=18, le=60, description="用户年龄(18-60岁)")
# 邮箱:必填,格式验证
email: EmailStr = Field(..., description="用户邮箱")
# 爱好:可选,列表类型
hobbies: List[str] = Field(default=[], description="用户爱好")
@app.post("/users/validate")
def create_validated_user(user: User):
return {"message": "用户创建成功", "data": user.dict()}
验证效果
- 若
name长度为 1,返回错误:{"detail":[{"loc":["body","name"],"msg":"ensure this value has at least 2 characters","type":"value_error.any_str.min_length","ctx":{"limit_value":2}}]}; - 若
email格式错误(如test.com),返回错误:{"detail":[{"loc":["body","email"],"msg":"value is not a valid email address","type":"value_error.email"}]}。
五、实战项目:构建完整的 TODO List API
结合前面的知识点,我们构建一个完整的 TODO List API,实现任务的 CRUD(创建、查询、更新、删除)操作,集成数据库、依赖注入、数据验证等功能。

5.1 项目结构
todo_api/
├── main.py # 主程序
└── requirements.txt # 依赖文件
5.2 依赖文件(requirements.txt)
fastapi>=0.100.0
uvicorn>=0.20.0
sqlalchemy>=2.0.0 # ORM数据库
pydantic>=2.0.0
python-multipart>=0.0.6
5.3 主程序(main.py)
from fastapi import FastAPI, Depends, HTTPException, status
from pydantic import BaseModel, Field
from sqlalchemy import create_engine, Column, Integer, String, Boolean
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Session
from typing import List, Optional
# ---------------------- 数据库配置 ----------------------
# 数据库连接地址(SQLite,文件型数据库,无需额外安装)
SQLALCHEMY_DATABASE_URL = "sqlite:///./todo.db"
# 创建数据库引擎
engine = create_engine(
SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False} # SQLite必需参数
)
# 创建会话本地类
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
# 声明基类
Base = declarative_base()
# ---------------------- 数据库模型 ----------------------
# TODO任务模型(对应数据库表)
class TodoDB(Base):
__tablename__ = "todos"
id = Column(Integer, primary_key=True, index=True)
title = Column(String, index=True, nullable=False) # 任务标题
description = Column(String, index=True, nullable=True) # 任务描述
completed = Column(Boolean, default=False) # 完成状态
# 创建数据库表(首次运行时执行)
Base.metadata.create_all(bind=engine)
# ---------------------- 依赖项 ----------------------
# 获取数据库会话
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
# ---------------------- Pydantic模型 ----------------------
# 请求模型:创建任务
class TodoCreate(BaseModel):
title: str = Field(..., min_length=1, max_length=100, description="任务标题")
description: Optional[str] = Field(None, max_length=500, description="任务描述")
# 响应模型:任务详情
class TodoResponse(BaseModel):
id: int
title: str
description: Optional[str]
completed: bool
class Config:
orm_mode = True # 支持ORM对象转换
# 请求模型:更新任务
class TodoUpdate(BaseModel):
title: Optional[str] = Field(None, min_length=1, max_length=100)
description: Optional[str] = Field(None, max_length=500)
completed: Optional[bool] = None
# ---------------------- FastAPI应用 ----------------------
app = FastAPI(title="TODO List API", description="基于FastAPI的任务管理API", version="1.0.0")
# ---------------------- 接口实现 ----------------------
# 1. 创建任务(POST)
@app.post("/todos", response_model=TodoResponse, status_code=status.HTTP_201)
def create_todo(todo: TodoCreate, db: Session = Depends(get_db)):
# 创建数据库对象
db_todo = TodoDB(
title=todo.title,
description=todo.description
)
# 添加到数据库
db.add(db_todo)
db.commit()
db.refresh(db_todo) # 刷新对象,获取自增ID
return db_todo
# 2. 查询所有任务(GET)
@app.get("/todos", response_model=List[TodoResponse])
def get_all_todos(
skip: int = 0, # 跳过前N条
limit: int = 10, # 最多返回N条
db: Session = Depends(get_db)
):
todos = db.query(TodoDB).offset(skip).limit(limit).all()
return todos
# 3. 查询单个任务(GET)
@app.get("/todos/{todo_id}", response_model=TodoResponse)
def get_todo(todo_id: int, db: Session = Depends(get_db)):
# 查询任务
todo = db.query(TodoDB).filter(TodoDB.id == todo_id).first()
# 任务不存在则返回404
if not todo:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"任务ID {todo_id} 不存在"
)
return todo
# 4. 更新任务(PUT)
@app.put("/todos/{todo_id}", response_model=TodoResponse)
def update_todo(
todo_id: int,
todo_update: TodoUpdate,
db: Session = Depends(get_db)
):
# 查询任务
todo = db.query(TodoDB).filter(TodoDB.id == todo_id).first()
if not todo:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"任务ID {todo_id} 不存在"
)
# 更新字段(只更新传入的非空字段)
if todo_update.title is not None:
todo.title = todo_update.title
if todo_update.description is not None:
todo.description = todo_update.description
if todo_update.completed is not None:
todo.completed = todo_update.completed
# 提交更新
db.commit()
db.refresh(todo)
return todo
# 5. 删除任务(DELETE)
@app.delete("/todos/{todo_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_todo(todo_id: int, db: Session = Depends(get_db)):
# 查询任务
todo = db.query(TodoDB).filter(TodoDB.id == todo_id).first()
if not todo:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"任务ID {todo_id} 不存在"
)
# 删除任务
db.delete(todo)
db.commit()
return None # 204状态码无返回内容
5.4 运行与测试
- 安装依赖:
pip install -r requirements.txt; - 启动服务:
uvicorn main:app --reload; - 访问 Swagger 文档:
http://127.0.0.1:8000/docs,测试所有接口。
测试流程
- 调用
/todos的 POST 接口,创建一个任务; - 调用
/todos的 GET 接口,查看所有任务; - 调用
/todos/{todo_id}的 GET 接口,查看单个任务; - 调用
/todos/{todo_id}的 PUT 接口,更新任务状态为完成; - 调用
/todos/{todo_id}的 DELETE 接口,删除任务。
六、部署上线:从开发环境到生产环境
6.1 生产环境启动(Uvicorn + Gunicorn)
开发环境使用uvicorn --reload,生产环境需要更稳定的部署方式,推荐使用Gunicorn作为进程管理器,搭配Uvicorn作为工作进程。

安装依赖
pip install gunicorn
启动命令
gunicorn -w 4 -k uvicorn.workers.UvicornWorker main:app --bind 0.0.0.0:8000
-w 4:启动 4 个工作进程(建议为 CPU 核心数的 2-4 倍);-k:指定工作进程类型为 UvicornWorker;--bind:绑定地址和端口,0.0.0.0 表示允许外部访问。
6.2 Docker 容器化部署
容器化部署能确保环境一致性,简化部署流程,以下是 Docker 部署步骤。
步骤 1:创建 Dockerfile
# 基础镜像
FROM python:3.9-slim
# 设置工作目录
WORKDIR /app
# 复制依赖文件
COPY requirements.txt .
# 安装依赖
RUN pip install --no-cache-dir -r requirements.txt
# 复制项目代码
COPY . .
# 暴露端口
EXPOSE 8000
# 启动命令
CMD ["gunicorn", "-w", "4", "-k", "uvicorn.workers.UvicornWorker", "main:app", "--bind", "0.0.0.0:8000"]
步骤 2:创建.dockerignore 文件
__pycache__/
*.pyc
*.pyo
*.pyd
.env
*.db
步骤 3:构建并运行容器
# 构建镜像
docker build -t todo-api .
# 运行容器
docker run -d -p 8000:8000 --name todo-api-container todo-api
访问 http://localhost:8000/docs,即可使用部署后的 API。
6.3 部署注意事项
- 密钥管理:生产环境中,SECRET_KEY、数据库连接地址等敏感信息应放在环境变量中,避免硬编码;
- 日志配置:配置日志输出,便于问题排查;
- 数据库迁移:使用 Alembic 管理数据库迁移,避免直接删除或修改表结构;
- HTTPS 配置:生产环境应启用 HTTPS,可通过 Nginx 反向代理实现。
七、避坑指南:常见问题与解决方案

7.1 坑点 1:路径参数与查询参数混淆
问题:误将路径参数写成查询参数,导致接口无法访问。示例:
# 错误:将user_id作为查询参数,却用了路径参数的URL
@app.get("/users")
def get_user(user_id: int):
return {"user_id": user_id}
解决方案:明确区分路径参数和查询参数,路径参数需在 URL 路径中定义:
# 正确:user_id为路径参数
@app.get("/users/{user_id}")
def get_user(user_id: int):
return {"user_id": user_id}
7.2 坑点 2:Pydantic 模型未启用 ORM 模式
问题:返回 ORM 对象时,提示 “value is not a valid dict”。解决方案:在响应模型中启用orm_mode = True:
class TodoResponse(BaseModel):
id: int
title: str
class Config:
orm_mode = True
7.3 坑点 3:异步接口中使用同步 IO 操作
问题:异步接口中使用同步数据库驱动(如 sqlite3),导致性能下降。解决方案:使用异步数据库驱动(如 asyncpg、motor),或在同步操作前加asyncio.to_thread:
# 同步操作转为异步
result = await asyncio.to_thread(sync_db_operation)
7.4 坑点 4:生产环境启用 reload 模式
问题:生产环境使用--reload参数,导致性能下降和安全风险。解决方案:生产环境启动时移除--reload参数。
八、总结:FastAPI 学习路径与进阶建议
8.1 核心要点回顾
- 基础功能:掌握路径参数、查询参数、请求体、响应模型的使用,这是 API 开发的基础;
- 进阶功能:依赖注入用于解耦代码,认证授权保护接口安全,异步处理提升并发性能;
- 实战能力:通过完整项目掌握数据库集成、接口设计、部署上线的全流程;
- 避坑技巧:注意参数类型、模型配置、异步操作、生产环境部署的细节。
8.2 进阶学习建议
- 深入 Pydantic:学习 Pydantic 的高级验证规则、模型嵌套、自定义验证器;
- WebSocket 支持:FastAPI 原生支持 WebSocket,可用于实时通信场景(如聊天、通知);
- 测试与文档:使用 pytest 测试 API,自定义接口文档内容;
- 性能优化:学习数据库索引优化、缓存使用、负载均衡等技巧。
FastAPI 的核心优势在于 “简单易用且高性能”,只要掌握核心知识点,多动手实战,就能快速构建出高质量的 API 服务。无论是个人项目还是企业级应用,FastAPI 都是 Python 开发者的优质选择。
2万+

被折叠的 条评论
为什么被折叠?



