简道云fastapi

This commit is contained in:
z66
2025-11-07 17:48:49 +08:00
commit 073f0646a1
30 changed files with 5933 additions and 0 deletions
+620
View File
@@ -0,0 +1,620 @@
# Flask 到 FastAPI 迁移指南
## 📋 目录
1. [迁移概览](#迁移概览)
2. [核心概念对比](#核心概念对比)
3. [代码迁移示例](#代码迁移示例)
4. [项目迁移分析](#项目迁移分析)
5. [常见迁移问题](#常见迁移问题)
---
## 迁移概览
### 为什么迁移到 FastAPI
1. **性能提升**FastAPI 性能接近 NodeJS 和 Go
2. **自动文档**:自动生成 API 文档
3. **类型安全**:基于 Python 类型提示
4. **异步支持**:原生支持 async/await
5. **现代特性**:符合现代 Python 开发标准
### 迁移步骤
1.**安装 FastAPI**`pip install fastapi uvicorn`
2.**替换应用实例**`Flask()``FastAPI()`
3.**更新路由装饰器**:基本语法相同
4.**处理异步**:添加 `async/await`
5.**数据验证**:使用 Pydantic 模型
6.**更新响应**:使用 FastAPI 响应类
---
## 核心概念对比
### 1. 应用实例
#### Flask
```python
from flask import Flask
app = Flask(__name__)
```
#### FastAPI
```python
from fastapi import FastAPI
app = FastAPI()
```
### 2. 路由定义
#### Flask
```python
@app.route('/items', methods=['GET'])
def get_items():
return jsonify({'items': []})
```
#### FastAPI
```python
@app.get('/items')
async def get_items():
return {'items': []}
```
**区别**
- FastAPI 使用 `@app.get()` 而不是 `@app.route(methods=['GET'])`
- FastAPI 函数通常是 `async`
- FastAPI 直接返回字典,自动转换为 JSON
### 3. 获取请求数据
#### Flask
```python
from flask import request
@app.route('/items', methods=['POST'])
def create_item():
data = request.get_json()
name = data.get('name')
return jsonify({'name': name})
```
#### FastAPI
```python
from fastapi import Request
from pydantic import BaseModel
class Item(BaseModel):
name: str
@app.post('/items')
async def create_item(item: Item):
return {'name': item.name}
```
**区别**
- FastAPI 使用 Pydantic 模型自动验证
- 不需要手动获取 JSON 数据
- 类型自动验证和转换
### 4. 路径参数
#### Flask
```python
@app.route('/items/<int:item_id>')
def get_item(item_id):
return jsonify({'item_id': item_id})
```
#### FastAPI
```python
@app.get('/items/{item_id}')
async def get_item(item_id: int):
return {'item_id': item_id}
```
**区别**
- FastAPI 使用 `{item_id}` 而不是 `<int:item_id>`
- 类型在函数参数中指定
### 5. 查询参数
#### Flask
```python
from flask import request
@app.route('/items')
def get_items():
skip = request.args.get('skip', 0, type=int)
limit = request.args.get('limit', 10, type=int)
return jsonify({'skip': skip, 'limit': limit})
```
#### FastAPI
```python
@app.get('/items')
async def get_items(skip: int = 0, limit: int = 10):
return {'skip': skip, 'limit': limit}
```
**区别**
- FastAPI 查询参数直接在函数参数中定义
- 默认值自动处理
- 类型自动验证
### 6. 请求头
#### Flask
```python
from flask import request
@app.route('/items')
def get_items():
user_agent = request.headers.get('User-Agent')
return jsonify({'user_agent': user_agent})
```
#### FastAPI
```python
from fastapi import Request, Header
@app.get('/items')
async def get_items(request: Request):
user_agent = request.headers.get('user-agent')
return {'user_agent': user_agent}
# 或者使用 Header
@app.get('/items')
async def get_items(user_agent: str = Header(None)):
return {'user_agent': user_agent}
```
### 7. 响应
#### Flask
```python
from flask import jsonify, Response
@app.route('/items')
def get_items():
return jsonify({'items': []})
# 或
return Response('text', mimetype='text/plain')
```
#### FastAPI
```python
from fastapi.responses import JSONResponse, PlainTextResponse
@app.get('/items')
async def get_items():
return {'items': []} # 自动转换为 JSON
# 或
return JSONResponse({'items': []})
# 或
return PlainTextResponse('text')
```
### 8. 错误处理
#### Flask
```python
from flask import abort
@app.route('/items/<int:item_id>')
def get_item(item_id):
if item_id not in items:
abort(404, description="Item not found")
return jsonify({'item_id': item_id})
```
#### FastAPI
```python
from fastapi import HTTPException
@app.get('/items/{item_id}')
async def get_item(item_id: int):
if item_id not in items:
raise HTTPException(status_code=404, detail="Item not found")
return {'item_id': item_id}
```
### 9. 应用状态
#### Flask
```python
from flask import g
@app.before_request
def before_request():
g.db = get_database()
@app.route('/items')
def get_items():
db = g.db
return jsonify({'items': []})
```
#### FastAPI
```python
@app.on_event("startup")
def startup():
app.state.db = get_database()
@app.get('/items')
async def get_items():
db = app.state.db
return {'items': []}
```
### 10. 中间件
#### Flask
```python
@app.before_request
def before_request():
# 请求前处理
pass
@app.after_request
def after_request(response):
# 请求后处理
response.headers['X-Custom'] = 'value'
return response
```
#### FastAPI
```python
@app.middleware("http")
async def add_custom_header(request: Request, call_next):
# 请求前处理
response = await call_next(request)
# 请求后处理
response.headers['X-Custom'] = 'value'
return response
```
---
## 代码迁移示例
### 示例 1:简单的 API 端点
#### Flask 版本
```python
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/api/users', methods=['POST'])
def create_user():
data = request.get_json()
if not data or 'name' not in data:
return jsonify({'error': '缺少 name 字段'}), 400
name = data['name']
age = data.get('age', 0)
return jsonify({'name': name, 'age': age}), 201
```
#### FastAPI 版本
```python
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
app = FastAPI()
class User(BaseModel):
name: str
age: int = 0
@app.post('/api/users', status_code=201)
async def create_user(user: User):
return {'name': user.name, 'age': user.age}
```
**改进点**
- ✅ 自动数据验证
- ✅ 类型安全
- ✅ 更简洁的代码
- ✅ 自动生成 API 文档
### 示例 2:带路径参数的端点
#### Flask 版本
```python
@app.route('/api/users/<int:user_id>', methods=['GET'])
def get_user(user_id):
if user_id not in users:
return jsonify({'error': '用户不存在'}), 404
return jsonify(users[user_id])
```
#### FastAPI 版本
```python
@app.get('/api/users/{user_id}')
async def get_user(user_id: int):
if user_id not in users:
raise HTTPException(status_code=404, detail='用户不存在')
return users[user_id]
```
### 示例 3:文件上传
#### Flask 版本
```python
from flask import request
@app.route('/upload', methods=['POST'])
def upload_file():
if 'file' not in request.files:
return jsonify({'error': '没有文件'}), 400
file = request.files['file']
# 处理文件
return jsonify({'filename': file.filename})
```
#### FastAPI 版本
```python
from fastapi import UploadFile, File
@app.post('/upload')
async def upload_file(file: UploadFile = File(...)):
# 处理文件
return {'filename': file.filename}
```
---
## 项目迁移分析
### 当前项目的迁移情况
#### 1. 应用初始化(main.py
**Flask 版本(推测)**
```python
from flask import Flask
app = Flask(__name__)
@app.before_first_request
def initialize():
app.config['app_tools'] = AppTools(Config)
# ...
```
**FastAPI 版本(当前)**
```python
from fastapi import FastAPI
app = FastAPI(title="简道云FastAPI服务")
@app.on_event("startup")
def on_startup():
app.state.app_tools = AppTools(Config)
app.state.logger = setup_global_logger(Config)
# ...
```
**迁移要点**
-`Flask()``FastAPI()`
-`@app.before_first_request``@app.on_event("startup")`
-`app.config``app.state`
#### 2. 路由处理(main.py
**Flask 版本(推测)**
```python
@app.route('/webhook', methods=['POST'])
def webhook():
data = request.get_json()
header = request.headers
# 处理逻辑
return jsonify(result)
```
**FastAPI 版本(当前)**
```python
@app.post("/webhook")
async def webhook(request: Request):
data = await request.json()
header = request.headers
# 处理逻辑
return JSONResponse(result)
```
**迁移要点**
-`@app.route(methods=['POST'])``@app.post()`
-`def``async def`
-`request.get_json()``await request.json()`
-`jsonify()``JSONResponse()` 或直接返回字典
#### 3. 任务队列处理
**项目特点**
- 使用自定义任务队列(`Queue` + `threading`
- 在异步函数中调用同步函数
**FastAPI 处理方式**
```python
# 在线程池中执行同步函数
result = await anyio.to_thread.run_sync(response_queue.get)
```
**迁移要点**
- ✅ 使用 `anyio.to_thread.run_sync()` 在线程池中执行同步代码
- ✅ 保持原有的任务队列机制
---
## 常见迁移问题
### Q1: 如何处理 Flask 的 `g` 对象?
**A:** 使用 `app.state` 或依赖注入:
```python
# Flask
from flask import g
g.db = get_db()
# FastAPI 方式 1:使用 app.state
app.state.db = get_db()
db = app.state.db
# FastAPI 方式 2:使用依赖注入(推荐)
def get_db():
db = "database"
yield db
@app.get("/items")
async def get_items(db: str = Depends(get_db)):
return {"db": db}
```
### Q2: 如何处理 Flask 的 `session`
**A:** FastAPI 不内置 session,需要手动实现或使用第三方库:
```python
from fastapi import FastAPI, Request
from starlette.middleware.sessions import SessionMiddleware
app = FastAPI()
app.add_middleware(SessionMiddleware, secret_key="secret")
@app.post("/login")
async def login(request: Request):
request.session['user'] = 'username'
return {"message": "Logged in"}
```
### Q3: 如何处理 Flask 的 `url_for`
**A:** 使用 `Request` 对象构建 URL
```python
from fastapi import Request
@app.get("/items/{item_id}")
async def get_item(item_id: int, request: Request):
url = str(request.url_for('get_item', item_id=item_id))
return {"url": url}
```
### Q4: 如何迁移 Flask 的蓝图(Blueprint)?
**A:** 使用 FastAPI 的 `APIRouter`
```python
from fastapi import APIRouter
router = APIRouter()
@router.get("/items")
async def get_items():
return {"items": []}
# 在主应用中注册
app.include_router(router, prefix="/api")
```
### Q5: 如何处理 Flask 的 `current_app`
**A:** 使用依赖注入或直接访问 `app`
```python
# Flask
from flask import current_app
config = current_app.config
# FastAPI
from fastapi import Request
@app.get("/config")
async def get_config(request: Request):
app = request.app
# 访问应用配置
return {"config": "value"}
```
### Q6: 如何迁移 Flask 的 `before_request` 和 `after_request`
**A:** 使用中间件:
```python
@app.middleware("http")
async def middleware(request: Request, call_next):
# before_request 逻辑
print("请求前")
response = await call_next(request)
# after_request 逻辑
print("请求后")
response.headers["X-Custom"] = "value"
return response
```
---
## 迁移检查清单
### 基础迁移
- [ ] 替换 `Flask()``FastAPI()`
- [ ] 更新路由装饰器(`@app.route()``@app.get()` 等)
- [ ] 添加 `async` 关键字
- [ ] 更新请求数据获取方式
- [ ] 更新响应返回方式
### 高级迁移
- [ ] 使用 Pydantic 模型进行数据验证
- [ ] 迁移应用状态(`app.config``app.state`
- [ ] 更新生命周期事件(`before_first_request``on_event("startup")`
- [ ] 迁移中间件
- [ ] 更新错误处理
### 测试和优化
- [ ] 测试所有 API 端点
- [ ] 验证数据验证功能
- [ ] 检查性能提升
- [ ] 更新文档
- [ ] 更新依赖项
---
## 总结
### 迁移优势
1. **性能提升**FastAPI 性能显著优于 Flask
2. **开发效率**:自动文档、自动验证减少开发时间
3. **类型安全**:类型提示提供更好的 IDE 支持
4. **现代特性**:异步支持、依赖注入等现代特性
### 注意事项
1. **异步编程**:需要理解 `async/await`
2. **Pydantic**:需要学习 Pydantic 模型定义
3. **依赖注入**:FastAPI 的依赖注入系统需要适应
4. **生态系统**:Flask 的某些扩展可能需要替代方案
### 建议
1. **逐步迁移**:不要一次性迁移所有代码
2. **保持兼容**:在迁移过程中保持 API 兼容性
3. **充分测试**:迁移后充分测试所有功能
4. **学习资源**:参考 FastAPI 官方文档和示例
---
**提示**:这个迁移指南帮助你理解从 Flask 到 FastAPI 的迁移过程。结合 `FASTAPI_LEARNING.md``FASTAPI_QUICK_REFERENCE.md` 一起学习效果更好。