# 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/') 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}` 而不是 `` - 类型在函数参数中指定 ### 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/') 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/', 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` 一起学习效果更好。