118 lines
3.1 KiB
Markdown
118 lines
3.1 KiB
Markdown
# SSE 到底是什么?用 FastAPI 一次讲透流式响应 | BV1if7E64Ex5
|
||
|
||
Milky 整理
|
||
|
||
## 一、三种通信协议对比
|
||
|
||
| 协议 | 类比 | 特点 |
|
||
|------|------|------|
|
||
| HTTP | 懒惰的服务员 | 你问一次,他答一次,服务器无法主动推送 |
|
||
| SSE | 勤快的服务员 | 只需要开口说一次,他会主动汇报最新进度 |
|
||
| WebSocket | 双方都带着对讲机 | 任何一方都可以随时主动说话,完全平等的双向通信 |
|
||
|
||
## 二、SSE 协议的适用场景
|
||
|
||
- **HTTP**:必须等模型生成完所有内容才能一次性返回,用户等待时间过长
|
||
- **WebSocket**:功能强大但成本高,且大多数 AI 场景中用户不需要主动发消息
|
||
- **SSE**:只发起一次请求,服务器边生成边推送,用户实时看到文字逐字出现
|
||
|
||
## 三、SSE 工作原理详解
|
||
|
||
### 完整流程
|
||
|
||
```
|
||
客户端 → 普通 HTTP 请求 → 服务器
|
||
客户端 ← Content-Type: text/event-stream ← 服务器
|
||
客户端 ← Connection: keep-alive ← 服务器
|
||
客户端 ← 持续推送事件数据 ← 服务器
|
||
客户端 ← event: done / data: [DONE] ← 服务器
|
||
```
|
||
|
||
### HTTP 响应头
|
||
|
||
```
|
||
Content-Type: text/event-stream
|
||
Cache-Control: no-cache
|
||
Connection: keep-alive
|
||
```
|
||
|
||
### SSE 消息格式
|
||
|
||
| 字段 | 作用 |
|
||
|------|------|
|
||
| data | 消息内容 |
|
||
| event | 事件类型 |
|
||
| id | 消息编号 |
|
||
| retry | 断线重连间隔(毫秒) |
|
||
|
||
每条消息之间用空行分隔。
|
||
|
||
### 浏览器端接收
|
||
|
||
```javascript
|
||
const source = new EventSource('/stream');
|
||
source.onmessage = (event) => {
|
||
console.log(event.data);
|
||
};
|
||
```
|
||
|
||
## 四、FastAPI 核心前置知识
|
||
|
||
- 与 Pydantic 深度绑定,自动请求解析和响应序列化
|
||
- 自动生成交互式 API 文档(/docs)
|
||
- 原生支持 async/await 异步编程
|
||
|
||
## 五、生成器(Generator)与 yield 关键字
|
||
|
||
yield 函数的四个特点:
|
||
1. 用 yield 代替 return
|
||
2. 执行到 yield 暂停并返回值
|
||
3. 下次调用从 yield 后继续
|
||
4. 按需产生数据,适合流式场景
|
||
|
||
## 六、完整 FastAPI SSE 实现
|
||
|
||
### 环境要求
|
||
|
||
```
|
||
FastAPI >= 0.135
|
||
```
|
||
|
||
### 代码
|
||
|
||
```python
|
||
from fastapi import FastAPI
|
||
from fastapi.responses import EventSourceResponse
|
||
from sse.starlette.sse import ServerSentEvent
|
||
from pydantic import BaseModel
|
||
|
||
app = FastAPI()
|
||
|
||
class ChatRequest(BaseModel):
|
||
message: str
|
||
|
||
@app.post("/stream")
|
||
async def stream_chat(request: ChatRequest):
|
||
async for chunk in model_stream(request.message):
|
||
if chunk == "[DONE]":
|
||
return
|
||
yield ServerSentEvent(data=chunk)
|
||
```
|
||
|
||
### 核心公式
|
||
|
||
```
|
||
EventSourceResponse + yield ServerSentEvent
|
||
```
|
||
|
||
## 七、三种协议总结对比
|
||
|
||
| 协议 | 实现复杂度 | 推送方向 | 适用场景 |
|
||
|------|-----------|----------|----------|
|
||
| HTTP | ⭐ 最简单 | 仅服务端响应 | 简单的一问一答 |
|
||
| SSE | ⭐⭐ 中等 | 服务端持续推送 | AI 流式输出、实时通知 |
|
||
| WebSocket | ⭐⭐⭐ 复杂 | 双向通信 | 需要客户端主动发消息的场景 |
|
||
|
||
──────────────────────────────
|
||
Generated by MilkyAi@Bilibili
|