You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 10:55:21