
使用 FastAPI 和 JavaScript 实现流式数据传输
引言
在现代 Web 应用中,实时数据传输变得越来越重要,特别是在处理大型 AI 模型响应、实时聊天或需要持续更新的数据时。本文将介绍如何使用 FastAPI 和 JavaScript 实现流式数据传输,并通过一个简单的示例来展示其实际应用。
什么是流式传输?
流式传输(Streaming)是一种数据传输方式,它允许数据分块发送,而不是等待所有数据准备就绪后一次性发送。这种方式有几个明显的优势:
更快的首次响应时间
更好的用户体验
更低的内存使用
实时数据更新
技术实现
让我们通过一个具体的例子来看看如何实现流式传输。
后端实现(FastAPI)
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
from fastapi.middleware.cors import CORSMiddleware
import asyncio
import json
app = FastAPI()
# 添加 CORS 中间件
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
async def ai_response_stream(prompt: str):
# 模拟 AI 响应
yield json.dumps({"message": prompt}) + "\n"
response = "这是一个很长的回答,我们需要分段发送。"
# 将回答按字符分段发送
for i in range(0, len(response), 2):
chunk = response[i:i+2]
yield json.dumps({"message": chunk}) + "\n"
await asyncio.sleep(1) # 控制发送速度
@app.post("/stream")
async def stream_endpoint(request: dict):
prompt = request.get("prompt", "")
return StreamingResponse(
ai_response_stream(prompt),
media_type='text/event-stream',
headers={
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Access-Control-Allow-Origin': '*',
}
)
前端实现(HTML/JavaScript)
<!DOCTYPE html>
<html>
<head>
<title>AI Stream Demo</title>
<style>
#container {
margin: 20px;
padding: 10px;
border: 1px solid #ccc;
min-height: 200px;
}
#input-area {
margin: 20px;
}
#prompt-input {
width: 300px;
padding: 5px;
}
</style>
</head>
<body>
<div id="input-area">
<input type="text" id="prompt-input" placeholder="输入你的问题">
<button onclick="fetchStream()">发送</button>
</div>
<div id="container"></div>
<script>
async function fetchStream() {
const promptInput = document.getElementById('prompt-input');
const prompt = promptInput.value;
if (!prompt.trim()) {
alert('请输入问题');
return;
}
// 清空之前的回答
const container = document.getElementById('container');
container.innerHTML = '';
try {
const response = await fetch('http://localhost:8000/stream', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ prompt: prompt })
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const {value, done} = await reader.read();
if (done) break;
const text = decoder.decode(value);
const lines = text.split('\n');
for (const line of lines) {
if (line.trim().length > 0) {
const data = JSON.parse(line);
if (data.error) {
updateUI({ message: `Error: ${data.error}` });
} else {
updateUI(data);
}
}
}
}
} catch (error) {
console.error('Error:', error);
updateUI({ message: `Error: ${error.message}` });
}
}
function updateUI(data) {
const container = document.getElementById('container');
if (data.message) {
// 使用 insertAdjacentHTML 而不是 innerHTML += 来优化性能
container.insertAdjacentHTML('beforeend', `<span>${data.message}</span>`);
}
}
</script>
</body>
</html>
工作原理解析
后端流程
初始化请求:当用户发送请求时,FastAPI 创建一个新的流式响应。
数据生成:使用异步生成器函数
ai_response_stream
逐步生成数据。数据传输:通过
StreamingResponse
将数据块逐个发送给客户端。
前端流程
发起请求:使用 Fetch API 发送 POST 请求。
数据接收:使用
ReadableStream
接口逐块读取响应数据。实时更新:将接收到的数据实时显示在页面上。
应用场景
流式传输特别适用于以下场景:
AI 对话系统:实时显示 AI 生成的回答。
实时聊天应用:即时消息传递。
大数据传输:分块传输大量数据。
实时数据分析:持续更新的数据可视化。
优势
更好的用户体验:用户无需等待完整响应即可看到数据。
资源效率:服务器可以逐步处理和发送数据,减少内存使用。
实时性:支持实时数据更新和显示。
可扩展性:适用于各种数据流场景。
注意事项
错误处理:确保正确处理连接中断等异常情况。
性能优化:合理控制数据传输速率和块大小。
浏览器兼容性:确保目标浏览器支持使用的 API。
安全性:在生产环境中实现适当的认证和授权机制。
结论
流式传输技术为现代 Web 应用提供了强大的数据传输能力,特别适合需要实时反馈的场景。通过 FastAPI 和现代浏览器 API 的结合,我们可以轻松实现高效的流式数据传输系统。
扩展阅读
希望这个教程能帮助你理解和实现流式数据传输!
这篇博客全面介绍了流式传输的概念、实现方式、应用场景和注意事项,适合想要了解和实现流式传输的开发者阅读。你可以根据需要调整内容的详细程度和技术深度。