711 lines
16 KiB
Markdown
711 lines
16 KiB
Markdown
# FastAPI 学习文档
|
||
|
||
## 📚 目录
|
||
|
||
1. [FastAPI 简介](#fastapi-简介)
|
||
2. [Flask vs FastAPI 对比](#flask-vs-fastapi-对比)
|
||
3. [FastAPI 核心概念](#fastapi-核心概念)
|
||
4. [项目中的 FastAPI 使用](#项目中的-fastapi-使用)
|
||
5. [学习路径建议](#学习路径建议)
|
||
6. [常见问题解答](#常见问题解答)
|
||
|
||
---
|
||
|
||
## FastAPI 简介
|
||
|
||
### 什么是 FastAPI?
|
||
|
||
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,基于 Python 3.6+ 的类型提示(type hints)。
|
||
|
||
### 主要特点
|
||
|
||
1. **高性能**:与 NodeJS 和 Go 相当,是最快的 Python 框架之一
|
||
2. **快速开发**:开发速度提升约 200% 到 300%
|
||
3. **自动文档**:自动生成交互式 API 文档(Swagger UI)
|
||
4. **类型提示**:基于 Python 类型提示,提供更好的 IDE 支持
|
||
5. **异步支持**:原生支持 async/await
|
||
6. **数据验证**:自动进行请求和响应数据验证
|
||
|
||
---
|
||
|
||
## Flask vs FastAPI 对比
|
||
|
||
### 1. 基本语法对比
|
||
|
||
#### Flask 写法
|
||
```python
|
||
from flask import Flask, request, jsonify
|
||
|
||
app = Flask(__name__)
|
||
|
||
@app.route('/webhook', methods=['POST'])
|
||
def webhook():
|
||
data = request.get_json()
|
||
return jsonify({'msg': 'success'})
|
||
```
|
||
|
||
#### FastAPI 写法
|
||
```python
|
||
from fastapi import FastAPI
|
||
from fastapi.responses import JSONResponse
|
||
from pydantic import BaseModel
|
||
|
||
app = FastAPI()
|
||
|
||
class RequestData(BaseModel):
|
||
name: str
|
||
age: int
|
||
|
||
@app.post("/webhook")
|
||
async def webhook(data: RequestData):
|
||
return JSONResponse({'msg': 'success'})
|
||
```
|
||
|
||
### 2. 主要区别
|
||
|
||
| 特性 | Flask | FastAPI |
|
||
|------|-------|---------|
|
||
| **异步支持** | 需要额外库(Flask-AsyncIO) | 原生支持 async/await |
|
||
| **类型验证** | 手动验证 | 自动验证(基于 Pydantic) |
|
||
| **API 文档** | 需要手动编写 | 自动生成(Swagger/OpenAPI) |
|
||
| **性能** | 中等 | 高性能(接近 NodeJS) |
|
||
| **依赖注入** | 需要额外库 | 内置支持 |
|
||
| **数据验证** | 手动处理 | 自动验证和转换 |
|
||
|
||
### 3. 请求处理对比
|
||
|
||
#### Flask
|
||
```python
|
||
from flask import request
|
||
|
||
@app.route('/api', methods=['POST'])
|
||
def api():
|
||
# 手动获取 JSON 数据
|
||
data = request.get_json()
|
||
# 手动验证
|
||
if not data or 'name' not in data:
|
||
return jsonify({'error': '缺少 name 字段'}), 400
|
||
return jsonify({'result': data['name']})
|
||
```
|
||
|
||
#### FastAPI
|
||
```python
|
||
from pydantic import BaseModel
|
||
|
||
class Item(BaseModel):
|
||
name: str
|
||
age: int
|
||
|
||
@app.post("/api")
|
||
async def api(item: Item):
|
||
# 自动验证,如果 name 缺失会自动返回 422 错误
|
||
return {'result': item.name}
|
||
```
|
||
|
||
---
|
||
|
||
## FastAPI 核心概念
|
||
|
||
### 1. 应用实例(FastAPI App)
|
||
|
||
```python
|
||
from fastapi import FastAPI
|
||
|
||
# 创建 FastAPI 应用实例
|
||
app = FastAPI(
|
||
title="简道云FastAPI服务", # API 文档标题
|
||
description="简道云 API 服务", # API 描述
|
||
version="1.0.0" # 版本号
|
||
)
|
||
```
|
||
|
||
**项目中的使用**(`main.py`):
|
||
```python
|
||
app = FastAPI(title="简道云FastAPI服务")
|
||
```
|
||
|
||
### 2. 路由装饰器(Route Decorators)
|
||
|
||
FastAPI 使用装饰器定义路由,类似于 Flask:
|
||
|
||
```python
|
||
@app.get("/") # GET 请求
|
||
@app.post("/") # POST 请求
|
||
@app.put("/") # PUT 请求
|
||
@app.delete("/") # DELETE 请求
|
||
```
|
||
|
||
**项目中的使用**(`main.py`):
|
||
```python
|
||
@app.post("/webhook")
|
||
async def webhook(request: Request):
|
||
# 处理逻辑
|
||
pass
|
||
```
|
||
|
||
### 3. 请求对象(Request)
|
||
|
||
FastAPI 的 `Request` 对象提供了访问请求信息的方法:
|
||
|
||
```python
|
||
from fastapi import Request
|
||
|
||
@app.post("/webhook")
|
||
async def webhook(request: Request):
|
||
# 获取 JSON 数据
|
||
data = await request.json()
|
||
|
||
# 获取请求头
|
||
headers = request.headers
|
||
|
||
# 获取查询参数
|
||
query_params = request.query_params
|
||
|
||
# 获取路径参数
|
||
path_params = request.path_params
|
||
```
|
||
|
||
**项目中的使用**(`main.py`):
|
||
```python
|
||
@app.post("/webhook")
|
||
async def webhook(request: Request):
|
||
# 获取请求数据
|
||
data = await request.json()
|
||
header = request.headers
|
||
|
||
# 解码请求头
|
||
decoded_header = app_tools.decode_headers(header)
|
||
```
|
||
|
||
### 4. 响应对象(Response)
|
||
|
||
FastAPI 提供了多种响应类型:
|
||
|
||
```python
|
||
from fastapi.responses import JSONResponse, HTMLResponse, PlainTextResponse
|
||
|
||
@app.post("/api")
|
||
async def api():
|
||
# JSON 响应
|
||
return JSONResponse({'msg': 'success'})
|
||
|
||
# 或者直接返回字典(FastAPI 会自动转换为 JSON)
|
||
return {'msg': 'success'}
|
||
```
|
||
|
||
**项目中的使用**(`main.py`):
|
||
```python
|
||
return JSONResponse(result)
|
||
```
|
||
|
||
### 5. 异步函数(Async Functions)
|
||
|
||
FastAPI 支持异步函数,使用 `async` 和 `await`:
|
||
|
||
```python
|
||
@app.post("/webhook")
|
||
async def webhook(request: Request):
|
||
# 异步获取 JSON 数据
|
||
data = await request.json()
|
||
|
||
# 异步调用其他函数
|
||
result = await some_async_function(data)
|
||
|
||
return result
|
||
```
|
||
|
||
**项目中的使用**(`main.py`):
|
||
```python
|
||
@app.post("/webhook")
|
||
async def webhook(request: Request):
|
||
data = await request.json() # 异步获取数据
|
||
# ...
|
||
result = await anyio.to_thread.run_sync(response_queue.get) # 异步执行同步函数
|
||
```
|
||
|
||
### 6. 生命周期事件(Lifecycle Events)
|
||
|
||
FastAPI 提供了应用启动和关闭事件:
|
||
|
||
```python
|
||
@app.on_event("startup")
|
||
async def startup_event():
|
||
"""应用启动时执行"""
|
||
print("应用启动")
|
||
|
||
@app.on_event("shutdown")
|
||
async def shutdown_event():
|
||
"""应用关闭时执行"""
|
||
print("应用关闭")
|
||
```
|
||
|
||
**项目中的使用**(`main.py`):
|
||
```python
|
||
@app.on_event("startup")
|
||
def on_startup():
|
||
"""应用启动时初始化"""
|
||
app.state.app_tools = AppTools(Config)
|
||
app.state.logger = setup_global_logger(Config)
|
||
app.state.f6_module = F6Module()
|
||
app.state.f6_plugin_module = F6PluginModule()
|
||
app.state.other_module = OtherPluginModule()
|
||
```
|
||
|
||
### 7. 应用状态(Application State)
|
||
|
||
FastAPI 允许在应用实例上存储状态:
|
||
|
||
```python
|
||
# 设置状态
|
||
app.state.my_data = "some value"
|
||
|
||
# 获取状态
|
||
my_data = app.state.my_data
|
||
```
|
||
|
||
**项目中的使用**(`main.py`):
|
||
```python
|
||
# 在启动时设置
|
||
app.state.app_tools = AppTools(Config)
|
||
app.state.logger = setup_global_logger(Config)
|
||
|
||
# 在路由中使用
|
||
logger = app.state.logger
|
||
app_tools: AppTools = app.state.app_tools
|
||
```
|
||
|
||
### 8. 数据验证(Pydantic Models)
|
||
|
||
FastAPI 使用 Pydantic 进行数据验证:
|
||
|
||
```python
|
||
from pydantic import BaseModel
|
||
|
||
class User(BaseModel):
|
||
name: str
|
||
age: int
|
||
email: str = None # 可选字段
|
||
|
||
@app.post("/users")
|
||
async def create_user(user: User):
|
||
# user 已经自动验证和转换
|
||
return {"name": user.name, "age": user.age}
|
||
```
|
||
|
||
**项目中的潜在使用**(可以改进):
|
||
```python
|
||
# 可以定义请求模型
|
||
class WebhookRequest(BaseModel):
|
||
api_key: str
|
||
entry_id: str
|
||
data_id: str
|
||
Action: str = None # 可选字段
|
||
|
||
@app.post("/webhook")
|
||
async def webhook(request: Request, data: WebhookRequest):
|
||
# data 已经自动验证
|
||
pass
|
||
```
|
||
|
||
---
|
||
|
||
## 项目中的 FastAPI 使用
|
||
|
||
### 1. 项目结构分析
|
||
|
||
```
|
||
fastapi_app/
|
||
├── main.py # FastAPI 应用入口
|
||
├── api.py # API 工具类(简道云 API 封装)
|
||
├── app/
|
||
│ ├── api.py # API 模块(简道云 API 封装)
|
||
│ ├── config.py # 配置管理
|
||
│ ├── module/ # 业务模块
|
||
│ ├── tasks/ # 后台任务
|
||
│ └── utils/ # 工具函数
|
||
└── requirements.txt # 依赖列表
|
||
```
|
||
|
||
### 2. main.py 详解
|
||
|
||
让我们逐步分析 `main.py` 文件:
|
||
|
||
#### 2.1 导入和初始化
|
||
|
||
```python
|
||
from fastapi import FastAPI, Request
|
||
from fastapi.responses import JSONResponse
|
||
import json
|
||
import anyio
|
||
from app.utils.app_tools import AppTools, setup_global_logger
|
||
from app.module.F6_Plugin_module import F6PluginModule
|
||
from app.module.module import F6Module
|
||
from app.module.other_module import OtherPluginModule
|
||
from app.config import Config
|
||
|
||
# 创建 FastAPI 应用实例
|
||
app = FastAPI(title="简道云FastAPI服务")
|
||
```
|
||
|
||
**说明**:
|
||
- `FastAPI`:主应用类
|
||
- `Request`:请求对象,用于访问请求信息
|
||
- `JSONResponse`:JSON 响应类
|
||
|
||
#### 2.2 启动事件
|
||
|
||
```python
|
||
@app.on_event("startup")
|
||
def on_startup():
|
||
"""应用启动时初始化"""
|
||
app.state.app_tools = AppTools(Config)
|
||
app.state.logger = setup_global_logger(Config)
|
||
app.state.f6_module = F6Module()
|
||
app.state.f6_plugin_module = F6PluginModule()
|
||
app.state.other_module = OtherPluginModule()
|
||
```
|
||
|
||
**说明**:
|
||
- `@app.on_event("startup")`:应用启动时执行
|
||
- `app.state`:存储应用级别的状态
|
||
- 初始化工具类、日志记录器和业务模块
|
||
|
||
#### 2.3 路由处理
|
||
|
||
```python
|
||
@app.post("/webhook")
|
||
async def webhook(request: Request):
|
||
"""
|
||
接受前端请求后将任务放入消息队列
|
||
|
||
Returns:
|
||
any: 返回任务处理的结果
|
||
"""
|
||
logger = app.state.logger
|
||
app_tools: AppTools = app.state.app_tools
|
||
|
||
# 获取请求数据
|
||
data = await request.json()
|
||
header = request.headers
|
||
|
||
# 解码请求头
|
||
decoded_header = app_tools.decode_headers(header)
|
||
|
||
# 获取操作映射表
|
||
action_map = get_action_map()
|
||
action = decoded_header.get('Action')
|
||
|
||
# 处理逻辑...
|
||
|
||
# 将任务放入消息队列
|
||
response_queue = app_tools.enqueue_task(handler, data)
|
||
|
||
# 等待任务处理结果
|
||
result = await anyio.to_thread.run_sync(response_queue.get)
|
||
|
||
logger.info(json.dumps(result, ensure_ascii=False, indent=4))
|
||
|
||
return JSONResponse(result)
|
||
```
|
||
|
||
**关键点**:
|
||
1. `async def`:异步函数定义
|
||
2. `await request.json()`:异步获取 JSON 数据
|
||
3. `await anyio.to_thread.run_sync()`:在线程池中执行同步函数
|
||
4. `JSONResponse`:返回 JSON 响应
|
||
|
||
### 3. 任务队列机制
|
||
|
||
项目使用自定义的任务队列来处理请求:
|
||
|
||
```python
|
||
# 在 app_tools.py 中
|
||
class AppTools:
|
||
def __init__(self, config):
|
||
self.task_queue = Queue()
|
||
self._start_task_thread()
|
||
|
||
def enqueue_task(self, handler, data):
|
||
response_queue = Queue()
|
||
self.task_queue.put({
|
||
'handler': handler,
|
||
'data': data,
|
||
'response': response_queue
|
||
})
|
||
return response_queue
|
||
```
|
||
|
||
**工作流程**:
|
||
1. 请求到达 `/webhook` 端点
|
||
2. 将任务放入队列
|
||
3. 后台线程处理任务
|
||
4. 等待结果返回
|
||
|
||
### 4. 操作映射机制
|
||
|
||
项目使用操作映射表来路由不同的操作:
|
||
|
||
```python
|
||
def get_action_map() -> dict:
|
||
"""获取操作映射表"""
|
||
f6_module = app.state.f6_module
|
||
f6_plugin_module = app.state.f6_plugin_module
|
||
other_module = app.state.other_module
|
||
return {
|
||
'login_in': f6_module.accept_login_message,
|
||
'get_company_information': f6_module.get_company_information,
|
||
'create_brand': f6_plugin_module.create_brand,
|
||
# ... 更多操作
|
||
}
|
||
```
|
||
|
||
**说明**:
|
||
- 通过请求头中的 `Action` 字段确定要执行的操作
|
||
- 使用字典映射操作名到处理函数
|
||
|
||
---
|
||
|
||
## 学习路径建议
|
||
|
||
### 阶段 1:基础理解(1-2 天)
|
||
|
||
1. **理解 FastAPI 基本概念**
|
||
- 阅读官方文档:https://fastapi.tiangolo.com/
|
||
- 理解路由、请求、响应的基本用法
|
||
|
||
2. **运行项目**
|
||
```bash
|
||
# 安装依赖
|
||
pip install -r requirements.txt
|
||
|
||
# 运行项目
|
||
python main.py
|
||
# 或
|
||
uvicorn main:app --reload
|
||
```
|
||
|
||
3. **访问 API 文档**
|
||
- 启动后访问:http://localhost:5003/docs
|
||
- 查看自动生成的 Swagger UI 文档
|
||
|
||
### 阶段 2:代码分析(2-3 天)
|
||
|
||
1. **分析 main.py**
|
||
- 理解应用初始化流程
|
||
- 理解路由处理逻辑
|
||
- 理解任务队列机制
|
||
|
||
2. **分析业务模块**
|
||
- 查看 `app/module/` 目录下的模块
|
||
- 理解操作映射机制
|
||
- 理解模块间的交互
|
||
|
||
3. **分析工具类**
|
||
- 查看 `app/utils/app_tools.py`
|
||
- 理解任务队列实现
|
||
- 理解日志记录机制
|
||
|
||
### 阶段 3:实践练习(3-5 天)
|
||
|
||
1. **添加新路由**
|
||
```python
|
||
@app.get("/health")
|
||
async def health_check():
|
||
return {"status": "ok"}
|
||
```
|
||
|
||
2. **添加数据验证**
|
||
```python
|
||
from pydantic import BaseModel
|
||
|
||
class WebhookData(BaseModel):
|
||
api_key: str
|
||
entry_id: str
|
||
data_id: str
|
||
|
||
@app.post("/webhook")
|
||
async def webhook(data: WebhookData):
|
||
return {"received": data.dict()}
|
||
```
|
||
|
||
3. **添加错误处理**
|
||
```python
|
||
from fastapi import HTTPException
|
||
|
||
@app.post("/webhook")
|
||
async def webhook(request: Request):
|
||
try:
|
||
data = await request.json()
|
||
# 处理逻辑
|
||
except Exception as e:
|
||
raise HTTPException(status_code=500, detail=str(e))
|
||
```
|
||
|
||
### 阶段 4:深入学习(1-2 周)
|
||
|
||
1. **学习异步编程**
|
||
- 理解 `async/await`
|
||
- 理解 `asyncio`
|
||
- 理解并发处理
|
||
|
||
2. **学习 Pydantic**
|
||
- 数据验证
|
||
- 数据序列化
|
||
- 自定义验证器
|
||
|
||
3. **学习依赖注入**
|
||
- FastAPI 的依赖注入系统
|
||
- 数据库连接管理
|
||
- 认证和授权
|
||
|
||
---
|
||
|
||
## 常见问题解答
|
||
|
||
### Q1: FastAPI 和 Flask 的主要区别是什么?
|
||
|
||
**A:** 主要区别:
|
||
1. **性能**:FastAPI 性能更高,支持异步
|
||
2. **类型验证**:FastAPI 自动验证,Flask 需要手动
|
||
3. **API 文档**:FastAPI 自动生成,Flask 需要手动编写
|
||
4. **异步支持**:FastAPI 原生支持,Flask 需要额外库
|
||
|
||
### Q2: 为什么使用 `async def` 而不是 `def`?
|
||
|
||
**A:**
|
||
- `async def` 允许使用 `await` 关键字
|
||
- 可以异步处理 I/O 操作(如网络请求、数据库查询)
|
||
- 提高并发性能
|
||
|
||
**示例**:
|
||
```python
|
||
# 同步(阻塞)
|
||
def sync_function():
|
||
data = requests.get("https://api.example.com") # 阻塞
|
||
return data
|
||
|
||
# 异步(非阻塞)
|
||
async def async_function():
|
||
async with httpx.AsyncClient() as client:
|
||
data = await client.get("https://api.example.com") # 非阻塞
|
||
return data
|
||
```
|
||
|
||
### Q3: `app.state` 是什么?为什么要用它?
|
||
|
||
**A:**
|
||
- `app.state` 是 FastAPI 提供的应用级状态存储
|
||
- 用于存储需要在多个路由之间共享的数据
|
||
- 类似于 Flask 的 `g` 对象,但作用域是整个应用
|
||
|
||
**项目中的使用**:
|
||
```python
|
||
# 启动时设置
|
||
app.state.logger = setup_global_logger(Config)
|
||
|
||
# 在路由中使用
|
||
logger = app.state.logger
|
||
```
|
||
|
||
### Q4: 如何处理同步函数?
|
||
|
||
**A:**
|
||
使用 `anyio.to_thread.run_sync()` 在线程池中执行同步函数:
|
||
|
||
```python
|
||
import anyio
|
||
|
||
# 同步函数
|
||
def sync_function(data):
|
||
# 耗时操作
|
||
return result
|
||
|
||
# 在异步函数中调用
|
||
@app.post("/api")
|
||
async def api(request: Request):
|
||
result = await anyio.to_thread.run_sync(sync_function, data)
|
||
return result
|
||
```
|
||
|
||
### Q5: 如何添加中间件?
|
||
|
||
**A:**
|
||
使用 `@app.middleware()` 装饰器:
|
||
|
||
```python
|
||
@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
|
||
response.headers["X-Process-Time"] = str(process_time)
|
||
return response
|
||
```
|
||
|
||
### Q6: 如何添加 CORS 支持?
|
||
|
||
**A:**
|
||
使用 `CORSMiddleware`:
|
||
|
||
```python
|
||
from fastapi.middleware.cors import CORSMiddleware
|
||
|
||
app.add_middleware(
|
||
CORSMiddleware,
|
||
allow_origins=["*"], # 允许所有源
|
||
allow_credentials=True,
|
||
allow_methods=["*"], # 允许所有方法
|
||
allow_headers=["*"], # 允许所有头
|
||
)
|
||
```
|
||
|
||
### Q7: 如何添加认证?
|
||
|
||
**A:**
|
||
使用依赖注入:
|
||
|
||
```python
|
||
from fastapi import Depends, HTTPException
|
||
from fastapi.security import HTTPBearer
|
||
|
||
security = HTTPBearer()
|
||
|
||
async def verify_token(token: str = Depends(security)):
|
||
if token != "valid_token":
|
||
raise HTTPException(status_code=401, detail="Invalid token")
|
||
return token
|
||
|
||
@app.post("/api")
|
||
async def api(token: str = Depends(verify_token)):
|
||
return {"message": "Authenticated"}
|
||
```
|
||
|
||
---
|
||
|
||
## 推荐资源
|
||
|
||
1. **官方文档**:https://fastapi.tiangolo.com/
|
||
2. **中文文档**:https://fastapi.tiangolo.com/zh/
|
||
3. **Pydantic 文档**:https://docs.pydantic.dev/
|
||
4. **Uvicorn 文档**:https://www.uvicorn.org/
|
||
|
||
---
|
||
|
||
## 总结
|
||
|
||
FastAPI 是一个现代、高性能的 Web 框架,特别适合构建 API。相比 Flask,它提供了:
|
||
|
||
1. **更好的性能**:异步支持,高性能
|
||
2. **自动验证**:基于类型提示的自动数据验证
|
||
3. **自动文档**:自动生成 API 文档
|
||
4. **更好的开发体验**:类型提示、IDE 支持
|
||
|
||
通过这个项目,你可以学习到:
|
||
- FastAPI 的基本用法
|
||
- 异步编程
|
||
- 任务队列机制
|
||
- 模块化架构设计
|
||
|
||
建议按照学习路径逐步深入,多实践、多思考,逐步掌握 FastAPI 的精髓。
|
||
|