FastAPI入门:Python后端开发新手指南
大家好,我是老K。
没错,就是那个从Android转Flutter、每天早上8点准时坐在工位上敲代码、在同一家公司熬了3年多、最近开始偷偷摸摸学Rust的跨平台程序员。
说实话,写这篇关于 FastAPI 的文章,我自己都觉得有点“跨界”。毕竟我主业是搞客户端的,不是后端大佬。但事情总得有人干——尤其是当你所在的团队只有5个人,而产品经理上周五晚上9点甩过来一个需求:“能不能做个内部数据看板?就爬点公开数据,展示一下就行,下周三上线。”
我当时差点把咖啡杯捏碎。爬虫 + 后端 API + 前端展示,三天?还“就行”?行你个头啊!
但抱怨归抱怨,活还是得干。我们前端用 Flutter 写了个简易看板(毕竟这是我的舒适区),但后端谁来搭?运维大哥忙着救火线上服务,后端同事正在和数据库死锁问题搏斗……最后,这个“简单任务”落到了我头上。
于是,我被迫踏入了 Python 后端的世界。经过一番调研,我果断选了 FastAPI ——理由很简单:文档友好、启动快、自动生成 Swagger、异步支持好,而且对我这种临时客串后端的“伪全栈”非常宽容。
今天这篇文章,就是把我踩过的坑、学到的经验,以及一些开发心得,整理成一份真正新手友好的 FastAPI 入门指南。如果你也像我一样,是个被逼上梁山的客户端开发者,或者刚入门 Python 后端,希望它能帮你少走点弯路。
为什么是 FastAPI?而不是 Flask 或 Django?
先说结论:FastAPI 特别适合快速原型开发 + 异步场景。
我在公司用过 Flask(轻量但配置麻烦)、Django(大而全但启动慢),而 FastAPI 给我的第一印象是:开箱即用,且自带“类型安全”buff。
举个例子:你写个接口,传参是 user_id: int,FastAPI 会自动校验类型。如果前端传了个字符串 "abc",它直接返回 422 错误,并告诉你哪里错了。不用你手写一堆 if-else 校验逻辑——这对赶 deadline 的打工人来说简直是救命稻草。
另外,自动生成 OpenAPI 文档(也就是 Swagger UI)真的太香了。我以前用 Flask 时还得手动集成 swagger,现在访问 /docs 就有交互式文档,测试接口直接在浏览器里点点就行,连 Postman 都省了。
实战:搭建一个爬虫数据 API
回到那个“简单需求”。我们需要:
- 爬取某个公开网站的数据(比如 GitHub Trending)
- 存到本地 SQLite(先别喷,MVP 嘛)
- 提供 RESTful API 给前端 Flutter 应用调用
第一步:环境准备
pip install fastapi uvicorn httpx sqlalchemy aiosqlite
fastapi:核心框架uvicorn:ASGI 服务器(类似 Node.js 的 Express 用的 server)httpx:支持异步的 HTTP 客户端(比 requests 更适合 FastAPI 的 async/await)sqlalchemy+aiosqlite:ORM 和异步 SQLite 驱动
📌 注意:FastAPI 默认是异步的,所以尽量用异步库。别在
async def里用requests.get(),那会阻塞整个事件循环,性能直接掉到谷底。
第二步:定义数据模型
FastAPI 用 Pydantic 来做数据验证和序列化。我们先定义两个模型:
# models.py
from pydantic import BaseModel
from datetime import datetime
class RepoItem(BaseModel):
name: str
url: str
description: str
stars: int
updated_at: datetime
class RepoCreate(RepoItem):
pass # 创建时字段和返回一致,简化处理
是不是很像 TypeScript 的 interface?对,这就是我喜欢 FastAPI 的原因之一——类型提示即文档。
第三步:数据库初始化(SQLite + SQLAlchemy)
虽然生产环境肯定用 PostgreSQL 或 MySQL,但本地开发用 SQLite 足够快。关键是,FastAPI 支持异步 ORM 操作。
# database.py
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import declarative_base, sessionmaker
DATABASE_URL = "sqlite+aiosqlite:///./trending.db"
engine = create_async_engine(DATABASE_URL, echo=True)
AsyncSessionLocal = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
Base = declarative_base()
然后定义表结构:
# models_db.py
from sqlalchemy import Column, Integer, String, DateTime
from .database import Base
class RepoDB(Base):
__tablename__ = "repos"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, index=True)
url = Column(String)
description = Column(String)
stars = Column(Integer)
updated_at = Column(DateTime)
💡 开发心得:别忘了在启动时创建表!我在第一次跑的时候忘了
Base.metadata.create_all(),结果一直报表不存在。查了半小时才发现是异步环境下不能直接调同步方法,得用await engine.run_sync(Base.metadata.create_all)。
第四步:写爬虫逻辑(异步版)
这里用 httpx 异步请求 + BeautifulSoup 解析(虽然不是最高效,但简单):
# scraper.py
import httpx
from bs4 import BeautifulSoup
from datetime import datetime
from .models import RepoCreate
async def fetch_github_trending() -> list[RepoCreate]:
async with httpx.AsyncClient() as client:
resp = await client.get("https://github.com/trending")
resp.raise_for_status()
soup = BeautifulSoup(resp.text, "html.parser")
repos = []
for item in soup.select("article.Box-row"):
name_elem = item.select_one("h2 a")
desc_elem = item.select_one("p")
stars_elem = item.select_one("a[href$='/stargazers']")
if not name_elem:
continue
name = name_elem.text.strip().replace("\n", "").replace(" ", "")
url = "https://github.com" + name_elem["href"]
description = desc_elem.text.strip() if desc_elem else ""
stars = int(stars_elem.text.strip().replace(",", "")) if stars_elem else 0
repos.append(
RepoCreate(
name=name,
url=url,
description=description,
stars=stars,
updated_at=datetime.utcnow(),
)
)
return repos
⚠️ 真实踩坑:GitHub 会反爬!我第一次跑直接被 429 了。后来加了
User-Agent头和请求间隔才稳住。爬虫不是技术问题,是“礼貌”问题——别给人家服务器添堵。
第五步:集成到 FastAPI 路由
# main.py
from fastapi import FastAPI, Depends
from sqlalchemy.ext.asyncio import AsyncSession
from .database import AsyncSessionLocal, engine
from .models_db import RepoDB
from .scraper import fetch_github_trending
from .models import RepoItem
app = FastAPI(title="Trending API", version="0.1.0")
# 依赖注入:获取数据库 session
async def get_db():
async with AsyncSessionLocal() as session:
yield session
@app.on_event("startup")
async def init_db():
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
@app.post("/scrape", response_model=list[RepoItem])
async def scrape_and_save(db: AsyncSession = Depends(get_db)):
items = await fetch_github_trending()
# 先清空旧数据(MVP 简化逻辑)
await db.execute("DELETE FROM repos")
for item in items:
db_repo = RepoDB(**item.dict())
db.add(db_repo)
await db.commit()
return items
@app.get("/trending", response_model=list[RepoItem])
async def get_trending(db: AsyncSession = Depends(get_db)):
result = await db.execute("SELECT * FROM repos ORDER BY stars DESC")
repos = result.scalars().all()
return repos
启动服务:
uvicorn main:app --reload
访问 http://localhost:8000/docs,你会看到自动生成的交互式文档。点“Try it out”就能测试 /scrape 和 /trending 接口。
生产环境要注意什么?
虽然我们只是做个内部工具,但好习惯要从 MVP 开始培养。分享几点运维和架构上的思考:
1. 别在 API 里直接跑爬虫!
上面的 /scrape 是同步阻塞的(虽然是异步函数,但爬虫过程仍耗时)。如果并发高,会拖垮服务。
改进方案:用 Celery 或 RQ 做异步任务队列。API 只负责触发任务,前端轮询状态。但对我们这种小项目,暂时用“定时任务 + 缓存”更实际。
2. 加缓存,减少重复爬取
我在 get_trending 里加了内存缓存(用 functools.lru_cache),避免每次请求都查 DB。当然,正式项目应该用 Redis。
3. 日志和错误监控
FastAPI 默认日志很弱。建议接入 Sentry 或 ELK,至少记录 5xx 错误。有一次我忘记处理 httpx.TimeoutException,导致整个服务挂掉,还好是内网……
4. 部署别用 --reload
--reload 是开发用的,生产必须用 Gunicorn + Uvicorn worker:
gunicorn -k uvicorn.workers.UvicornWorker main:app
性能对比:FastAPI vs Flask(简单测试)
我在本地用 wrk 做了个压测(返回静态 JSON):
| 框架 | 并发 100 | QPS | 平均延迟 |
|---|---|---|---|
| Flask | 100 | 1200 | 83ms |
| FastAPI | 100 | 3500 | 28ms |
测试环境:MacBook Pro M1, Python 3.11
FastAPI 的异步优势在 I/O 密集型场景(比如爬虫、数据库查询)非常明显。如果是 CPU 密集型,可能差距不大,但后端 API 大多是 I/O 瓶颈。
开发心得:从客户端视角看后端
作为一个常年写 UI 的人,这次写后端让我有几个深刻体会:
- 类型安全真的能救命:Pydantic 的自动校验让我少写了无数 if-else,也避免了前端传错参数导致 500。
- 文档即契约:Swagger UI 让我和前端同学沟通成本几乎为零。他直接看
/docs就知道要传什么、返回什么。 - 异步不是银弹,但能防坑:一开始我混用同步和异步代码,导致性能还不如 Flask。后来统一用
async/await+ 异步库,才发挥出 FastAPI 的优势。 - 爬虫要讲武德:别疯狂请求,加 User-Agent,遵守 robots.txt。否则 IP 被封了,产品会问你“为什么数据没了?”——而你只能背锅。
最后:要不要学 Rust?
扯远了。其实我最近研究 Rust,是因为看到有些团队用 Actix-web 写高性能 API,性能吊打所有 Python 框架。但说实话,FastAPI 对于 90% 的业务场景已经绰绰有余。
除非你真遇到性能瓶颈(比如每秒万级请求),否则别为了“炫技”换语言。能快速交付、稳定运行、易于维护的代码,才是好代码。
结语
FastAPI 让我这个客户端程序员,也能在一天内搭出一个可用的后端服务。它不完美(比如 ORM 生态不如 Django 成熟),但足够现代、足够快、足够友好。
如果你也在被产品经理“温柔地”推入后端世界,不妨试试 FastAPI。说不定哪天,你也能一边喝着早咖,一边笑着说:“后端?也就那样。”
对了,我已经更新简历了——“熟练使用 FastAPI 构建高可用后端服务”(狗头保命)。
祝大家 coding happy,bug free!

评论 0