如何用Axios(React前端)接收Flask服务器yield推送的流数据?
解决React接收Flask流式响应的方案
你的后端通过yield实现了流式数据推送,但普通的axios请求会等待整个响应完成才返回结果,无法处理持续推送的数据流。下面是具体的解决方案:
一、后端小调整(关键)
为了让前端能准确拆分每个推送的JSON数据,需要在每个yield的消息末尾添加换行符,避免多个JSON拼接在一起无法解析:
def redis_stream(): global lock channel = r.pubsub() channel.subscribe('CellGridMapClose') for msg in channel.listen(): if msg['type'] == 'message': obj = tm.CellGridMapping() obj.ParseFromString(msg['data']) objects = obj.objects movement = [] for vehicle in objects: x, y = vehicle.pos.x, vehicle.pos.y movement.append({'posx': x/50, 'posy': y/40}) # 每个消息末尾添加换行符,方便前端分割 yield json.dumps(movement) + '\n'
路由部分保持不变:
@app.route('/redis-stream') def redis_data(): return Response(redis_stream(), mimetype='application/json')
如果存在跨域问题,需要给Flask配置CORS:
from flask_cors import CORS app = Flask(__name__) # 生产环境建议指定具体允许的域名,比如CORS(app, resources={"/redis-stream": {"origins": "https://your-frontend-domain.com"}}) CORS(app)
二、前端实现(使用Fetch API)
浏览器原生的Fetch API支持直接读取ReadableStream,可以逐块处理后端推送的数据流:
import { useEffect, useState } from 'react'; function StreamComponent() { const [movementData, setMovementData] = useState([]); async function listenToStream() { try { const response = await fetch('/redis-stream'); if (!response.ok) { throw new Error(`请求失败: ${response.status}`); } const reader = response.body.getReader(); const decoder = new TextDecoder('utf-8'); let remainingText = ''; while (true) { const { done, value } = await reader.read(); if (done) { console.log('数据流已结束'); break; } // 把字节解码为文本,拼接之前剩余的内容 const chunk = decoder.decode(value, { stream: true }); const fullText = remainingText + chunk; // 按换行符拆分多个消息 const messages = fullText.split('\n'); // 最后一个元素可能不完整,留到下一次处理 remainingText = messages.pop() || ''; // 解析每个消息为JSON并更新状态 for (const msg of messages) { if (!msg.trim()) continue; try { const data = JSON.parse(msg); setMovementData(prev => [...prev, ...data]); console.log('收到新数据:', data); } catch (err) { console.error('解析JSON失败:', err); } } } } catch (err) { console.error('监听数据流出错:', err); } } useEffect(() => { listenToStream(); // 组件卸载时可调用reader.cancel()终止流读取 return () => {}; }, []); return ( <div> <h3>实时车辆位置</h3> {movementData.map((pos, index) => ( <div key={index}> X: {pos.posx.toFixed(2)}, Y: {pos.posy.toFixed(2)} </div> ))} </div> ); } export default StreamComponent;
三、为什么不用axios?
浏览器环境下的axios不支持stream类型的响应(仅Node.js支持),虽然可以尝试responseType: 'blob'或onDownloadProgress,但无法像Fetch API一样便捷地逐块处理流式数据,因此推荐使用原生Fetch方案。
内容的提问来源于stack exchange,提问作者Vladi Yudi
相关产品推荐
相关产品推荐

