目录
『宝藏代码胶囊开张啦!』—— 我的 CodeCapsule 来咯!✨
写代码不再头疼!我的新站点 CodeCapsule 主打一个 “白菜价”+“量身定制”!无论是卡脖子的毕设/课设/文献复现,需要灵光一现的算法改进,还是想给项目加个“外挂”,这里都有便宜又好用的代码方案等你发现!低成本,高适配,助你轻松通关!速来围观 CodeCapsule官网
在为下一个API项目选择技术栈时,Flask和FastAPI无疑是Python开发者最常考虑的两个选择。为了帮助你直观理解它们的核心差异,下面这个表格从多个维度对两者进行了全面对比:
| 特性维度 | Flask | FastAPI |
|---|---|---|
| 底层协议 | WSGI(同步) | ASGI(异步) |
| 性能表现 | 中等,同步阻塞 | 高,异步非阻塞,可达Flask 2-3倍吞吐量 |
| 学习曲线 | 平缓,适合初学者 | 中等,需掌握类型提示和异步编程 |
| 类型系统 | 动态类型,无强制约束 | 强类型驱动,深度集成Type Hints |
| 数据验证 | 需手动或第三方库(如Marshmallow) | 内置Pydantic,自动校验 |
| API文档 | 需扩展(如Flask-RESTx) | 自动生成OpenAPI(Swagger UI/ReDoc) |
| 异步支持 | 2.0+支持但生态同步为主 | 原生async/await |
| 生态系统 | 丰富成熟的扩展 | 年轻但增长迅速 |
| 代码简洁性 | 灵活但需更多样板代码 | 减少约50%样板代码 |
接下来,让我们深入探讨这两个框架的具体特点和使用方法。
1 Flask:灵活轻量的微框架
1.1 设计哲学与特点
Flask于2010年诞生,遵循"微框架"设计理念,只提供Web开发的核心功能(如路由、请求响应处理),其他功能通过丰富的扩展生态实现。这种设计赋予开发者极高的灵活性。
1.2 基础代码示例
from flask import Flask, request, jsonify
from werkzeug.exceptions import BadRequest
app = Flask(__name__)
# 手动数据验证辅助函数
def validate_user_data(data):
"""验证用户数据"""
if not data:
raise BadRequest('No JSON data provided')
if 'name' not in data or not isinstance(data['name'], str):
raise BadRequest('Name is required and must be a string')
if 'age' not in data or not isinstance(data['age'], int):
raise BadRequest('Age is required and must be an integer')
if data['age'] < 0:
raise BadRequest('Age must be non-negative')
return True
@app.route('/users', methods=['POST'])
def create_user():
"""
创建用户端点
手动处理JSON解析、验证和错误处理
"""
# 手动检查Content-Type
if not request.is_json:
return jsonify({'error': 'Content-Type must be application/json'}), 400
try:
data = request.get_json()
except Exception:
return jsonify({'error': 'Invalid JSON data'}), 400
# 手动验证数据
try:
validate_user_data(data)
except BadRequest as e:
return jsonify({'error': str(e)}), 400
# 处理业务逻辑
user_id = 123 # 模拟ID生成
return jsonify({
'id': user_id,
'name': data['name'],
'age': data['age']
}), 201
@app.route('/users/<int:user_id>', methods=['GET'])
def get_user(user_id):
"""
获取用户信息
路径参数验证由Flask自动处理
"""
# 模拟用户数据
user = {'id': user_id, 'name': 'Alice', 'age': 30}
return jsonify(user)
if __name__ == '__main__':
app.run(debug=True)
1.3 代码解读与框架特点
- 手动验证:需要自行处理JSON解析和数据类型验证
- 显式错误处理:每个可能的错误点都需要手动返回适当的HTTP响应
- 灵活的路由:使用装饰器定义路由,支持动态URL参数
- 扩展依赖:如需自动API文档,需集成Flask-RESTx等扩展
2 FastAPI:现代高性能API框架
2.1 设计哲学与特点
FastAPI诞生于2018年,专为构建现代API而设计。它基于Python类型提示、异步编程和开放标准(如OpenAPI),在提供高性能的同时,显著提升开发效率。
2.2 基础代码示例
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, Field
from typing import Optional
app = FastAPI(title="User API", version="1.0.0")
# 使用Pydantic定义数据模型
class UserCreate(BaseModel):
"""用户创建数据模型"""
name: str = Field(..., min_length=1, max_length=50, example="Alice")
age: int = Field(..., ge=0, le=150, example=25)
email: Optional[str] = Field(None, example="alice@example.com")
# Pydantic验证示例
@validator('name')
def validate_name(cls, v):
if not v.strip():
raise ValueError('Name cannot be empty or whitespace only')
return v.title()
class UserResponse(BaseModel):
"""用户响应数据模型"""
id: int
name: str
age: int
email: Optional[str]
@app.post("/users", response_model=UserResponse, status_code=201)
async def create_user(user: UserCreate):
"""
创建用户
- **name**: 用户姓名,1-50字符
- **age**: 年龄,0-150之间
- **email**: 可选邮箱
"""
# 异步操作示例 - 模拟数据库保存
user_id = await save_user_to_database(user)
return UserResponse(
id=user_id,
name=user.name,
age=user.age,
email=user.email
)
@app.get("/users/{user_id}", response_model=UserResponse)
async def get_user(user_id: int):
"""
根据ID获取用户信息
- **user_id**: 用户ID (路径参数)
"""
user = await fetch_user_from_database(user_id)
if not user:
raise HTTPException(status_code=404, detail="User not found")
return user
# 模拟异步数据库操作
async def save_user_to_database(user: UserCreate) -> int:
"""模拟异步用户保存"""
# 实际项目中这里可能是SQLAlchemy、Tortoise-ORM等异步操作
return 123
async def fetch_user_from_database(user_id: int) -> Optional[UserResponse]:
"""模拟异步用户查询"""
if user_id == 123:
return UserResponse(id=123, name="Alice", age=25, email="alice@example.com")
return None
# 运行命令: uvicorn main:app --reload
2.3 代码解读与框架特点
- 类型驱动开发:Python类型提示用于自动验证、序列化和文档生成
- 自动API文档:启动服务后访问
/docs(Swagger UI)和/redoc即可获得交互式文档 - 异步原生:原生支持async/await,适合I/O密集型操作
- 数据模型中心化:使用Pydantic模型定义API契约,减少重复代码
3 性能对比:数据说话
3.1 架构差异与性能影响
两个框架的性能差异主要源于其底层架构:
从架构图可以看出,FastAPI的ASGI异步架构使其在高并发场景下具有显著性能优势。
3.2 实际性能数据
根据测试数据,在相同硬件条件下:
- FastAPI:每秒可处理约28, 000-35, 000个请求
- Flask:每秒可处理约2, 800-9, 000个请求
这意味着在I/O密集型场景(如数据库查询、外部API调用)中,FastAPI的性能可达Flask的2-3倍甚至更高。
4 开发体验与生态系统
4.1 学习曲线对比
Flask学习路径:
- 优点:API简洁,概念简单,适合初学者
- 缺点:大型项目缺乏规范,易变成"面条代码"
FastAPI学习路径:
- 优点:类型驱动开发提供更好的代码提示和错误检测
- 挑战:需要理解异步编程、类型提示和Pydantic
4.2 生态系统比较
Flask生态系统:
- 优势:扩展丰富成熟(Flask-SQLAlchemy、Flask-Login、Flask-Admin等)
- 特点:社区庞大稳定,有大量最佳实践
FastAPI生态系统:
- 现状:相对年轻但增长迅速
- 优势:兼容Starlette中间件生态系统,关键库(如SQLAlchemy)已支持异步
5 决策指南:如何选择
5.1 选择Flask的场景
✅ 小型Web应用和API:快速原型开发、内部工具
✅ 需要特定Flask扩展:依赖Flask-Admin、Flask-WTF等成熟扩展的传统项目
✅ 团队初学者友好:团队成员Python经验有限,需要平缓学习曲线
✅ 传统同步架构:项目依赖大量同步库,迁移到异步成本过高
5.2 选择FastAPI的场景
✅ 高性能RESTful API:需要处理高并发请求的生产级API
✅ 微服务架构:轻量级、高性能的微服务,易于容器化部署
✅ 机器学习/AI服务:快速将模型封装为高性能API接口
✅ 强类型和自动化:重视类型安全、自动文档和开发效率
✅ 实时功能:需要WebSocket、Server-Sent Events等实时通信
5.3 决策流程图
6 完整示例:同一个API的两种实现
6.1 任务管理API - Flask实现
from flask import Flask, request, jsonify
from flask.views import MethodView
from functools import wraps
import json
app = Flask(__name__)
# 内存存储
tasks = []
next_id = 1
# 简单认证装饰器
def require_api_key(f):
@wraps(f)
def decorated_function(*args, **kwargs):
api_key = request.headers.get('X-API-Key')
if not api_key or api_key != 'secret-key':
return jsonify({'error': 'Valid API key required'}), 401
return f(*args, **kwargs)
return decorated_function
class TaskAPI(MethodView):
@require_api_key
def get(self, task_id=None):
if task_id:
task = next((t for t in tasks if t['id'] == task_id), None)
if not task:
return jsonify({'error': 'Task not found'}), 404
return jsonify(task)
else:
status = request.args.get('status')
if status:
filtered_tasks = [t for t in tasks if t['status'] == status]
return jsonify(filtered_tasks)
return jsonify(tasks)
@require_api_key
def post(self):
global next_id
if not request.is_json:
return jsonify({'error': 'Content-Type must be application/json'}), 400
data = request.get_json()
# 手动验证
if not data.get('title'):
return jsonify({'error': 'Title is required'}), 400
task = {
'id': next_id,
'title': data['title'],
'description': data.get('description', ''),
'status': 'pending'
}
tasks.append(task)
next_id += 1
return jsonify(task), 201
@require_api_key
def put(self, task_id):
if not request.is_json:
return jsonify({'error': 'Content-Type must be application/json'}), 400
data = request.get_json()
task = next((t for t in tasks if t['id'] == task_id), None)
if not task:
return jsonify({'error': 'Task not found'}), 404
# 手动更新字段
if 'title' in data:
task['title'] = data['title']
if 'description' in data:
task['description'] = data.get('description', '')
if 'status' in data and data['status'] in ['pending', 'in_progress', 'completed']:
task['status'] = data['status']
return jsonify(task)
@require_api_key
def delete(self, task_id):
global tasks
task = next((t for t in tasks if t['id'] == task_id), None)
if not task:
return jsonify({'error': 'Task not found'}), 404
tasks = [t for t in tasks if t['id'] != task_id]
return '', 204
# 注册路由
app.add_url_rule('/tasks', view_func=TaskAPI.as_view('tasks'))
app.add_url_rule('/tasks/<int:task_id>', view_func=TaskAPI.as_view('task'))
if __name__ == '__main__':
app.run(debug=True)
6.2 任务管理API - FastAPI实现
from fastapi import FastAPI, HTTPException, Depends, status
from pydantic import BaseModel, Field
from typing import List, Optional
from enum import Enum
app = FastAPI(title="Task Management API", version="1.0.0")
# 枚举和模型定义
class TaskStatus(str, Enum):
PENDING = "pending"
IN_PROGRESS = "in_progress"
COMPLETED = "completed"
class TaskBase(BaseModel):
title: str = Field(..., min_length=1, max_length=100, example="Buy groceries")
description: Optional[str] = Field(None, example="Milk, Eggs, Bread")
status: TaskStatus = Field(default=TaskStatus.PENDING, example="pending")
class TaskCreate(TaskBase):
pass
class TaskResponse(TaskBase):
id: int
class Config:
orm_mode = True
# 依赖项 - 认证
async def verify_api_key(x_api_key: str = Header(...)):
if x_api_key != "secret-key":
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Valid API key required"
)
return True
# 内存存储
tasks_db = []
next_id = 1
@app.get("/tasks", response_model=List[TaskResponse])
async def list_tasks(
status: Optional[TaskStatus] = None,
authenticated: bool = Depends(verify_api_key)
):
"""获取任务列表,可选状态过滤"""
if status:
return [task for task in tasks_db if task["status"] == status]
return tasks_db
@app.get("/tasks/{task_id}", response_model=TaskResponse)
async def get_task(
task_id: int,
authenticated: bool = Depends(verify_api_key)
):
"""根据ID获取任务详情"""
task = next((t for t in tasks_db if t["id"] == task_id), None)
if not task:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Task not found"
)
return task
@app.post("/tasks", response_model=TaskResponse, status_code=status.HTTP_201_CREATED)
async def create_task(
task: TaskCreate,
authenticated: bool = Depends(verify_api_key)
):
"""创建新任务"""
global next_id
task_data = task.dict()
task_data["id"] = next_id
tasks_db.append(task_data)
next_id += 1
return task_data
@app.put("/tasks/{task_id}", response_model=TaskResponse)
async def update_task(
task_id: int,
task_update: TaskCreate,
authenticated: bool = Depends(verify_api_key)
):
"""更新任务"""
existing_task = next((t for t in tasks_db if t["id"] == task_id), None)
if not existing_task:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Task not found"
)
# 更新字段
update_data = task_update.dict(exclude_unset=True)
for field, value in update_data.items():
existing_task[field] = value
return existing_task
@app.delete("/tasks/{task_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_task(
task_id: int,
authenticated: bool = Depends(verify_api_key)
):
"""删除任务"""
global tasks_db
task = next((t for t in tasks_db if t["id"] == task_id), None)
if not task:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Task not found"
)
tasks_db = [t for t in tasks_db if t["id"] != task_id]
return None
# 运行: uvicorn main:app --reload
6.3 两种实现的关键差异分析
- 验证逻辑:Flask需要手动验证,FastAPI通过Pydantic自动处理
- 依赖管理:Flask使用装饰器,FastAPI使用依赖注入系统
- 错误处理:Flask手动返回错误响应,FastAPI抛出标准异常
- 文档生成:FastAPI自动生成OpenAPI文档,Flask需要额外扩展
7 迁移策略:从Flask到FastAPI
如果你有现有的Flask项目考虑迁移到FastAPI,建议采用渐进式策略:
7.1 并行运行策略
# 在现有Flask应用中逐步引入FastAPI
from flask import Flask
from fastapi import FastAPI as FastAPIApp
import asyncio
flask_app = Flask(__name__)
fastapi_app = FastAPIApp()
# 新端点使用FastAPI,旧端点保持Flask
@flask_app.route('/legacy-endpoint')
def legacy_endpoint():
return "This is legacy Flask endpoint"
# 通过代理或API网关将不同路径路由到不同应用
7.2 关键迁移步骤
- 从简单端点开始:先迁移数据模型和简单GET端点
- 保持API兼容性:确保URL结构和响应格式不变
- 逐步迁移:按模块或功能逐步迁移,而非一次性重写
- 充分测试:利用FastAPI的TestClient进行自动化测试
结论
Flask和FastAPI都是优秀的Python Web框架,但各有最适合的场景:
- 选择Flask:当项目规模较小、需要快速原型、依赖特定Flask扩展,或团队对异步编程尚不熟悉时
- 选择FastAPI:当构建高性能API、需要自动文档、重视类型安全,或项目涉及高并发和异步操作时
从行业趋势看,FastAPI在2025年已成为增长最快的Python框架,特别适合现代云原生和微服务架构。如果你的项目以API为中心,且追求性能和开发效率,FastAPI是更面向未来的选择。
无论选择哪个框架,重要的是根据项目需求、团队技能和长期维护成本做出明智决策。两个框架都有其存在的价值,在Python Web开发生态中各自发挥着重要作用。
浙公网安备 33010602011771号