FastAPI入门:Python后端开发新手指南
上周五晚上十一点半,我刚在新公司提交完一个紧急需求的代码,顺手点开招聘网站看了眼——果然又有一堆JD写着“熟悉FastAPI优先”。我苦笑一下,摸了摸咖啡杯底残留的冰块。这已经是我入职新公司的第二个月了,从滴滴干了四年司机端核心业务的老油条,突然切换到一家创业公司搞新项目,技术栈大换血不说,连写接口都得重新学怎么“优雅”。
其实我在滴滴那会儿,主力是Go + Gin,偶尔用Flask搭个内部工具。FastAPI?听说过,但总觉得“不就是个Python框架嘛,能有啥不一样?”直到上个月产品提了个需求:要三天内上线一个司机行为分析的对外API服务,要求高并发、低延迟、还得自动生成文档给合作方调用。我第一反应是:“完了,又要熬夜。” 但转念一想,不如趁机把FastAPI啃下来?
为什么是 FastAPI?不是 Flask/Django?
说实话,一开始我是抗拒的。毕竟在滴滴,我们对性能抠得特别细——双11那种高峰日,司机端每秒几万请求,一个慢查询就能让整个调度系统抖三抖。Python 在我印象里,一直是“脚本语言”,写工具还行,扛生产流量?心里打鼓。
但现实逼人。团队人少、deadline紧、合作方又催着要 OpenAPI 文档。我翻了翻 FastAPI 的文档,发现它有几个点直接戳中痛点:
- 自动 OpenAPI/Swagger UI:不用手动维护接口文档,对接第三方省下至少两天沟通成本
- Pydantic 模型校验:参数校验再也不用手写 if-else 堆成山
- 异步支持(async/await):配合 Uvicorn,理论上能扛住比 Flask 高好几倍的 QPS
- 类型提示原生支持:作为被 Go 惯坏的人,看到
def create_driver(data: DriverCreate) -> DriverResponse这种签名简直热泪盈眶
小声吐槽:产品经理上次说“这个接口很简单,就传个ID查个状态”,结果上线后发现没做限流,差点把数据库干趴。现在有了 Pydantic + FastAPI 的自动校验,至少烂参数进不到业务逻辑层——运维兄弟应该会感谢我。
踩坑实录:从“Hello World”到线上跑稳
刚开始写 demo 的时候,一切都很美好:
from fastapi import FastAPI
app = FastAPI()
@app.get("/drivers/{driver_id}")
def get_driver(driver_id: int):
return {"driver_id": driver_id, "name": "张师傅"}
跑起来,访问 /docs,Swagger UI 自动出来,还能在线调试。我当时心想:“这不比 Flask 香?”
但很快现实就教我做人。
坑1:异步不是万能的,尤其当你连数据库驱动都没切对
我兴冲冲地把 PostgreSQL 查询写成 async:
import asyncio
import asyncpg
@app.get("/drivers/{driver_id}")
async def get_driver(driver_id: int):
conn = await asyncpg.connect("postgresql://...")
row = await conn.fetchrow("SELECT * FROM drivers WHERE id = $1", driver_id)
await conn.close()
return row
本地测试没问题。但压测一上,QPS 卡在 200 不动。我盯着监控看了半小时,终于意识到:每次请求都新建数据库连接?这不是自杀吗!
赶紧换成连接池:
from databases import Database
database = Database("postgresql+asyncpg://...")
@app.on_event("startup")
async def startup():
await database.connect()
@app.on_event("shutdown")
async def shutdown():
await database.disconnect()
@app.get("/drivers/{driver_id}")
async def get_driver(driver_id: int):
query = "SELECT * FROM drivers WHERE id = :driver_id"
return await database.fetch_one(query, values={"driver_id": driver_id})
QPS 直接飙到 1500+。那一刻我深刻理解了什么叫“异步只是手段,资源复用才是王道”。
坑2:Pydantic 模型别乱继承,小心序列化爆炸
为了复用字段,我搞了个基类:
class BaseModel(BaseModel):
id: int
created_at: datetime
class Driver(BaseModel):
name: str
phone: str
结果返回 JSON 时,created_at 变成了 {} —— 因为 Pydantic 默认不处理 datetime 序列化!查了半天文档才发现要加配置:
class Config:
json_encoders = {datetime: lambda v: v.isoformat()}
或者更简单:直接用 .model_dump() 替代 dict(model)。
这种细节,在面试题里可能就是一句“Pydantic 如何处理非 JSON 原生类型?”,但在生产环境,可能就是半夜三点被 PagerDuty 叫醒的原因。
架构设计思考:别只顾着写接口
在滴滴那会儿,我们有个铁律:任何新服务上线前,必须回答三个问题:
- 流量来了怎么办?(扩缩容)
- 接口挂了怎么办?(熔断降级)
- 数据错了怎么办?(可追溯)
FastAPI 虽然快,但不代表你可以忽略架构。
我做了几件事:
- 中间件统一处理日志和 trace_id:方便链路追踪
- 用 Redis 做缓存穿透保护:司机信息查不到也设个空值,避免 DB 被击穿
- 接口加 rate limit:用
slowapi包,按 IP 限流 - 健康检查接口:K8s 就靠它判断 pod 是否 ready
from fastapi import Request
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
limiter = Limiter(key_func=get_remote_address)
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
@app.get("/drivers/{driver_id}")
@limiter.limit("100/minute")
async def get_driver(request: Request, driver_id: int):
# ...
上线一周,没出 P0 事故。运维大哥终于没在群里@我了,感动。
性能对比:FastAPI 到底快多少?
闲着无聊,我拿 Flask 和 FastAPI 同样逻辑压测了下(Uvicorn vs Gunicorn+Gevent):
| 框架 | 并发 100 | QPS | 平均延迟 |
|---|---|---|---|
| Flask | 100 | 320 | 312ms |
| FastAPI (sync) | 100 | 480 | 208ms |
| FastAPI (async) | 100 | 1650 | 60ms |
数据仅供参考,但结论很明显:如果你的 I/O 密集(比如查 DB、调外部 API),异步 FastAPI 能榨干机器性能。不过要注意,CPU 密集型任务(比如图像处理)还是扔给 Celery 或者直接用 Go 更合适。
开发心得 & 给新人的建议
作为一个从“老派后端”转型的人,我的真心话:
- 别被“快”迷惑:FastAPI 快,但你的 SQL 慢,照样拉胯。记得 explain 你的查询。
- 善用依赖注入:
Depends()看似花哨,但解耦数据库、权限、上下文超有用。 - 测试不能省:FastAPI 官方推荐用
TestClient,写单元测试比 Flask 顺手太多。 - 别在 main.py 写业务:分层!models / schemas / crud / api / core,该拆就拆。
至于面试题挑战?最近面了几个候选人,问“FastAPI 为什么快”,有人答“因为用了 Starlette”,这没错,但更深层的是:基于 ASGI 的异步模型 + Pydantic 的 C 扩展加速 + 类型提示带来的编译期优化。能聊到这层,基本就过了。
结语
写这篇文章的时候,已经是凌晨两点。窗外北京的夜很安静,只有键盘咔嗒声。回想这两个月,从抗拒到真香,FastAPI 确实让我重新爱上了 Python 后端开发——不是因为它多炫酷,而是它在保持 Python 简洁的同时,给了你接近 Go 的工程能力。
如果你也是刚入行的 Python 新手,或者像我一样从别的语言转过来,不妨试试 FastAPI。它可能不会让你一夜暴富,但至少能让你在 deadline 前睡个好觉(大概)。
对了,刚收到产品消息:“下周要加个实时位置推送接口……”
算了,不说了,我去研究 WebSocket 了。

评论 0