Contents

FastAPI vs Flask

参考资料

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
pip install 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)