参考资料
FastAPI 简介
FastAPI 是一个基于 ASGI(异步服务器网关接口)的框架,使用 Pydantic 进行数据验证,Starlette + Uvicorn 提供异步请求能力。
与 Flask 不同,FastAPI 没有内置开发服务器,需要使用 Uvicorn 这样的 ASGI 服务器运行。
安装:
1
|
pip install fastapi uvicorn
|
示例:
1
2
3
4
5
6
7
8
9
10
11
|
import uvicorn
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def home():
return {"hello": "world"}
if __name__ == "__main__":
uvicorn.run("fastapi_code:app", reload=True)
|
环境变量
Flask
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
import os
from flask import Flask
class Config(object):
MESSAGE = os.environ.get("MESSAGE")
app = Flask(__name__)
# 直接从类中获取配置信息
app.config.from_object(Config)
@app.route("/settings")
def get_settings():
return {"message": app.config["MESSAGE"]}
if __name__ == "__main__":
app.run()
|
FastAPI
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
import uvicorn
from fastapi import FastAPI
from pydantic import BaseSettings
class Settings(BaseSettings):
message: str
settings = Settings()
app = FastAPI()
@app.get("/settings")
def get_settings():
# 读取类实例的属性
return { "message": settings.message }
if __name__ == "__main__":
uvicorn.run("fastapi_code:app")
|
运行前记得设置环境变量:export MESSAGE="hello, world"
HTTP 请求方法
Flask
1
2
3
4
5
6
7
|
from flask import request
@app.route("/", methods=["GET", "POST"])
def home():
if request.method == "POST":
return {"Hello": "POST"}
return {"Hello": "GET"}
|
FastAPI
需要为每个 HTTP 方法提供单独的装饰器:
1
2
3
4
5
6
7
8
9
10
|
@app.get("/")
def home():
return {"Hello": "GET"}
@app.post("/")
def home_post():
return {"Hello": "POST"}
# @app.delete("/")
# @app.patch("/")
|
URL 参数
Flask
1
2
3
|
@app.route("/employee/<int:id>", methods=["GET"])
def home(id):
return {"id": id}
|
通过 URL 路径传递参数。
FastAPI
1
2
3
|
@app.get("/employee/{id}")
def home(id: int):
return {"id": id}
|
URL 参数类似 f-string 表达式,id: int 的类型提示告诉 Pydantic 进行自动验证。
查询参数
Flask
1
2
3
4
5
6
|
from flask import request
@app.route("/employee", methods=["GET"])
def home():
department = request.args.get("department")
return {"department": department}
|
获取 URL 中 /employee?department=sales 的查询参数。
FastAPI
1
2
3
|
@app.get("/employee")
def home(department: str):
return {"department": department}
|
函数参数自动映射为查询参数。
模板渲染
Flask
1
2
3
4
5
|
from flask import render_template
@app.route("/")
def home():
return render_template("index.html")
|
内置模板支持。
FastAPI
需要安装 Jinja2:
1
2
3
4
5
6
7
8
9
10
11
12
|
from fastapi import Request
from fastapi.templating import Jinja2Templates
from fastapi.responses import HTMLResponse
app = FastAPI()
# 明确地定义 "模板" 文件夹
templates = Jinja2Templates(directory="templates")
@app.get("/", response_class=HTMLResponse)
def home(request: Request):
return templates.TemplateResponse("index.html", {"request": request})
|
需要显式定义模板目录。
静态文件
Flask
默认从 static 文件夹中获取静态文件。
FastAPI
需要显式挂载静态文件目录:
1
2
3
4
|
from fastapi.staticfiles import StaticFiles
app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
|
异步任务
Flask
Flask >= 2.0 支持异步:
1
2
3
4
|
@app.route("/")
async def home():
result = await some_async_task()
return result
|
FastAPI
对 asyncio 原生支持,只需在视图函数中添加 async 关键字:
1
2
3
4
|
@app.get("/")
async def home():
result = await some_async_task()
return result
|
依赖注入
Flask
Flask 通过装饰器和上下文实现简单的依赖注入,通常需要借助第三方库如 Flask-Injector。
FastAPI
FastAPI 内置强大的依赖注入系统:
1
2
3
4
5
6
7
8
|
from fastapi import Depends
def get_query_param():
return "default"
@app.get("/")
async def home(value: str = Depends(get_query_param)):
return {"value": value}
|
依赖项可以是函数、类或可调用对象,支持层级依赖、自动垃圾回收等特性。
数据校验
FastAPI
使用 Pydantic 进行自动数据验证:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
from pydantic import BaseModel
app = FastAPI()
class Request(BaseModel):
username: str
password: str
@app.post("/login")
async def login(req: Request):
if req.username == "testdriven.io" and req.password == "testdriven.io":
return {"message": "success"}
return {"message": "Authentication Failed"}
|
当请求体缺少必要字段时,Pydantic 会自动返回详细的错误信息。
Flask 没有内置的数据校验机制,通常需要使用 Flask-WTF 或手动校验。
响应序列化
Flask
1
2
3
4
5
6
|
from flask import jsonify
from data import get_data_as_dict
@app.route("/")
def send_data():
return jsonify(get_data_as_dict())
|
需要使用 jsonify 将字典转换为 JSON 响应。
FastAPI
自动序列化任何返回的字典或其他 Pydantic 模型:
1
2
3
|
@app.get("/")
def send_data():
return get_data_as_dict()
|
无需手动调用 jsonify。
中间件
Flask
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
import time
class Middleware:
def __init__(self, app) -> None:
self.app = app
def __call__(self, environ, start_response):
start = time.time()
response = self.app(environ, start_response)
end = time.time() - start
print(f"request processed in {end} s")
return response
app = Flask(__name__)
app.wsgi_app = Middleware(app.wsgi_app)
|
该中间件用于计算请求处理耗时。
FastAPI
1
2
3
4
5
6
7
8
9
|
from fastapi import Request
@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
print(f"request processed in {process_time} s")
return response
|
支持异步中间件。
模块化路由
Flask
1
2
3
4
5
6
7
8
|
# blueprints/product/views.py
from flask import Blueprint
product = Blueprint("product", __name__)
@product.route("/product1")
def product_view():
...
|
1
2
3
4
|
# main.py
from blueprints.product.views import product
app.register_blueprint(product)
|
FastAPI
1
2
3
4
5
6
7
8
|
# routers/product/views.py
from fastapi import APIRouter
product = APIRouter()
@product.get("/product1")
def product_view():
...
|
1
2
3
4
|
# main.py
from routers.product.views import product
app.include_router(product)
|
| 框架 |
组件名称 |
注册方法 |
| Flask |
Blueprint |
register_blueprint |
| FastAPI |
APIRouter |
include_router |
测试
Flask
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
import pytest
from flask import Flask
app = Flask(__name__)
@app.route("/")
def home():
return {"message": "OK"}
def test_hello():
res = app.test_client().get("/")
assert res.status_code == 200
assert res.data == b'{"message":"OK"}\n'
|
FastAPI
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
from fastapi import FastAPI
from fastapi.testclient import TestClient
app = FastAPI()
@app.get("/")
async def home():
return {"message": "OK"}
client = TestClient(app)
def test_home():
res = client.get("/")
assert res.status_code == 200
assert res.json() == {"message": "OK"}
|
Docker 部署
Flask
1
2
3
4
5
6
7
8
9
10
11
12
|
FROM python3.10-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 5000
CMD ["gunicorn", "main:app"]
|
生产环境使用 Gunicorn 作为 WSGI 服务器。
FastAPI
1
2
3
4
5
6
7
8
9
10
11
12
|
FROM python3.10-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0"]
|
开发和生产环境都可以使用 Uvicorn。
框架特性对比
| 特性 |
Flask |
FastAPI |
| API 文档 |
需安装 flask-swagger |
自动生成 Swagger/OpenAPI 文档 |
| CORS |
需安装 flask-cors |
原生支持 |
| 开发服务器 |
内置(调试用) |
需使用 Uvicorn |
| 生产服务器 |
推荐使用 Gunicorn |
使用 Uvicorn |
| 数据校验 |
手动或 Flask-WTF |
Pydantic 自动校验 |
| 异步支持 |
Flask >= 2.0 支持 |
原生异步支持 |
| 依赖注入 |
需第三方库 |
内置强大支持 |
| 序列化 |
需手动 jsonify |
自动序列化 |
拓展与后续学习建议
延伸阅读方向:
- 框架选型:根据项目需求选择合适的框架——FastAPI 适合高并发 API 服务,Flask 适合中小型项目和需要灵活定制的场景
- ASGI 生态:深入了解 ASGI 规范,学习 Uvicorn、Hypercorn 等 ASGI 服务器
- Pydantic 高级用法:学习 Pydantic 的高级特性,如自定义验证器、嵌套模型、配置类等
高阶应用场景:
- 微服务架构:使用 FastAPI 构建高性能微服务,结合 Docker 和 Kubernetes 实现容器化部署
- 实时通信:结合 FastAPI 和 WebSocket 实现实时功能
- 后台任务:学习 FastAPI 的后台任务(Background Tasks)和 Celery 集成
- 类型安全:利用 FastAPI 的类型提示实现端到端的类型安全,包括前端代码生成(openapi-generator)