FastAPI入门:Python后端开发新手指南
上周五晚上十点半,我正蹲在县城老家的阳台上,一边啃着我妈刚蒸好的红薯,一边用 VSCode 调试一个接口。窗外是零星的路灯和偶尔路过的三轮车,而我的终端里却在疯狂刷着 422 Unprocessable Entity 的报错——那一刻我真的想把笔记本扔进隔壁池塘。
但转念一想,这不就是我最近准备跳槽、硬着头皮学 FastAPI 的日常吗?作为一个典型的“小镇做题家”,远程办公三年多,从 jQuery 写到 Vue3,前端动画搞了一堆,结果领导上个月突然甩过来一句话:“后端也得懂点,不然怎么和后端同学对齐?” 好吧,我承认,其实是我想跳槽去一线城市的大厂,简历上不能只有“精通 CSS 动画”这种听起来像美工的描述。
于是,FastAPI 成了我的新战场。今天这篇笔记,就是我踩坑、翻车、重装、再爬起来的真实记录。不讲虚的,全是实操。如果你也是和我一样的 Python 新手后端,或者正被面试题挑战逼得头秃,这篇或许能帮你少走点弯路。
为啥选 FastAPI?不是 Flask 吗?
说实话,一开始我也觉得 Flask 够用了。毕竟我们公司那个内部管理系统,用 Flask + SQLAlchemy 撑了两年多,连双11大促(虽然只是个本地电商节)都没崩。但问题来了——文档。
产品经理每次提需求,都要问:“这个接口参数啥格式?返回啥结构?” 我只能截图 Postman 或者手写 Markdown。测试同事更惨,光靠肉眼核对接口字段,漏掉一个 is_vip 字段,上线后用户积分直接清零,运维半夜打电话骂我祖宗十八代。
FastAPI 最打动我的,是它自带 OpenAPI 文档 + 自动校验。你定义好 Pydantic 模型,接口文档自动生成,连 Swagger UI 都给你配好了。更狠的是,传参不对?直接 422 报错,连脏数据都进不了业务逻辑。
小镇做题家的觉悟:代码可以烂,但接口必须干净。
环境搭建:别让工具拖后腿
我在县城用的是联通 50M 宽带,pip install 经常卡死。所以第一步,先换源:
pip install fastapi uvicorn[standard] -i https://pypi.tuna.tsinghua.edu.cn/simple/
注意,一定要装 uvicorn[standard],否则静态文件、WebSocket 这些高级功能会报错。我第一次只装了 uvicorn,结果跑个 WebSocket 聊天室直接崩了,查了三天才发现是没装 websockets 依赖。
VSCode 插件我也堆满了:
- Python
- Pylance
- REST Client(用来直接在编辑器里发请求)
- Thunder Client(Postman 替代品,轻量)
- Error Lens(把报错信息直接标在代码行上,救命神器)
启动服务?一行命令搞定:
uvicorn main:app --reload --port 8000
--reload 是开发模式自动重启,但千万别在生产环境开!我上周不小心把 dev 配置推到测试环境,结果每次有人 git push,服务就重启一次,运维差点把我拉黑。
第一个接口:从“Hello World”到面试题挑战
FastAPI 的 hello world 简直优雅到哭:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"message": "县城码农在此"}
但现实哪有这么简单?上周面试一家杭州的公司,第一道题就是:“用 FastAPI 实现一个用户注册接口,要求邮箱格式校验、密码强度 ≥8 位、手机号唯一性检查。”
我当时心里咯噔一下——这不就是我最近练的题吗!
关键在于 Pydantic 模型。它不仅是数据载体,更是校验规则:
from pydantic import BaseModel, validator
import re
class UserCreate(BaseModel):
email: str
password: str
phone: str
@validator('email')
def validate_email(cls, v):
if not re.match(r"[^@]+@[^@]+\.[^@]+", v):
raise ValueError('邮箱格式错误')
return v
@validator('password')
def validate_password(cls, v):
if len(v) < 8:
raise ValueError('密码至少8位')
return v
然后在接口里直接用:
@app.post("/register")
def register(user: UserCreate):
# 这里已经自动校验过了,放心用 user.email
if db.phone_exists(user.phone):
return {"error": "手机号已注册"}
db.create_user(user)
return {"status": "success"}
重点来了:所有校验都在进入业务逻辑前完成。这意味着你的核心代码不用再写一堆 if-else 判断参数合法性——这不就是面试官想听的“防御性编程”吗?
数据库怎么搞?别再裸写 SQL 了
我们小县城项目之前用的是原生 SQLite + 手写 SQL,直到某次上线改了个字段名,忘了改查询语句,整个订单模块瘫痪两小时。自那以后,我发誓要用 ORM。
FastAPI 官方推荐搭配 SQLModel(作者也是 FastAPI 的 creator),它融合了 Pydantic 和 SQLAlchemy 的优点。比如用户表:
from sqlmodel import SQLModel, Field, create_engine, Session
class User(SQLModel, table=True):
id: int = Field(default=None, primary_key=True)
email: str = Field(unique=True)
password: str
phone: str = Field(unique=True)
engine = create_engine("sqlite:///./test.db")
SQLModel.metadata.create_all(engine)
插入数据?简洁到离谱:
with Session(engine) as session:
session.add(User(email="a@b.com", password="12345678", phone="13800138000"))
session.commit()
更爽的是,Pydantic 模型和数据库模型可以复用。你甚至可以直接把 User 当作接口响应模型返回(记得隐藏密码字段):
from pydantic import field_validator
class UserPublic(BaseModel):
id: int
email: str
phone: str
@field_validator('phone', mode='before')
def mask_phone(cls, v):
return v[:3] + '****' + v[-4:] # 138****8000
性能与架构:别以为 FastAPI 快就乱来
FastAPI 基于 Starlette 和 Pydantic,异步支持一流。但很多新手(包括我)一上来就狂写 async def,结果数据库还是同步操作,性能反而更差。
记住:异步只在 I/O 密集型场景才有优势。如果你的接口主要在查数据库、调第三方 API,才考虑 async。否则,同步代码更简单、调试更容易。
我们线上环境用的是 Gunicorn + Uvicorn worker,配置如下:
gunicorn -k uvicorn.workers.UvicornWorker main:app -w 4 -b 0.0.0.0:8000 --timeout 60
为什么 4 个 worker?因为我们服务器是 4 核。别盲目加进程,上下文切换开销会让你哭。
另外,不要在接口里直接操作文件或长时间计算。有一次我写了个导出 Excel 功能,直接在接口里生成文件,结果并发一高,内存爆了。后来改成 Celery 异步任务 + Redis 队列,稳如老狗。
生产环境那些坑:运维不会告诉你的事
FastAPI 开发爽,但上线才是真正的考验。分享几个血泪教训:
1. 日志别只 print
开发时 print("debug") 很爽,但生产环境必须用 structured logging。我用的是 loguru:
from loguru import logger
logger.add("logs/app.log", rotation="500 MB")
logger.info("User {} registered", user.email)
2. CORS 跨域问题
前端同事在 Vue 里调接口,一直报 CORS error。其实 FastAPI 有官方中间件:
from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
CORSMiddleware,
allow_origins=["https://your-frontend.com"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
别偷懒写 allow_origins=["*"],会被安全扫描打回来。
3. 健康检查接口
K8s 或 Docker Swarm 需要 /health 接口判断服务是否存活:
@app.get("/health")
def health_check():
return {"status": "ok", "db": "connected" if db.ping() else "down"}
资源推荐:小镇做题家的自学包
最后放点干货资源,全是亲测有效的:
| 类型 | 名称 | 说明 |
|---|---|---|
| 官方文档 | FastAPI 官网 | 英文好,例子全,必看 |
| 中文教程 | FastAPI 中文文档 | 翻译质量不错 |
| 视频课 | Corey Schafer 的 FastAPI 系列 | YouTube 免费,讲解细致 |
| GitHub 项目 | full-stack-fastapi-postgresql | 官方推荐的完整项目模板 |
| 面试题 | LeetCode “API Design” 标签 | 结合 FastAPI 实现 |
特别推荐那个 full-stack-fastapi-postgresql 项目,连 Dockerfile、Nginx 配置、用户认证、权限控制都给你写好了。我直接 fork 下来改,三天就搭出 MVP。
写在最后:从县城到大厂,代码是唯一的船票
学 FastAPI 这一个月,我刷了 30+ 道后端面试题,写了两个小项目,还帮公司重构了旧接口。上周四,终于收到一家深圳公司的二面通知——岗位是“全栈工程师”,要求熟悉 FastAPI。
我知道,县城的夜晚很安静,但代码跑起来的声音,比任何喧嚣都响亮。
FastAPI 不是银弹,但它让我这个前端出身的“伪后端”看到了希望:用现代工具,写清晰代码,做可靠系统。这不就是我们小镇做题家最擅长的事吗?
所以,别管你在哪座小城,只要终端还能连上 GitHub,键盘还能敲出逻辑,你就永远有机会。
对了,刚提交的 PR 又被测试打回来了——说手机号脱敏规则错了。得,红薯也凉了,继续改 bug 吧。
(完)

评论 0