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

Flask流响应更新异常求助:无法实时推送内容

问题:Flask流响应无法实时推送到前端

参考相关示例代码测试Flask流响应更新时,出现以下问题:后端Python控制台每秒正常输出Line X,但前端无法实时获取数据,最终一次性接收全部内容。

测试代码

Flask后端代码

from flask import Response, Flask, render_template
import time

app = Flask(__name__)

@app.route('/')
def main():
    return render_template('index2.html')

def generate_text_stream():
    for i in range(10):
        time.sleep(1)
        print(f"Line {i}\n")
        yield f"Line {i}\n"

@app.route('/stream')
def text_stream():
    return Response(generate_text_stream(), mimetype='text/plain')

app.run(debug=False)

前端HTML代码

<p>This is the latest output: <span id="latest"></span></p>
<p>This is all the output:</p>
<ul id="output"></ul>
<script>
    var latest = document.getElementById('latest');
    var output = document.getElementById('output');

    var xhr = new XMLHttpRequest();
    xhr.open('GET', '/stream');
    xhr.send();
    var position = 0;

    function handleNewData() {
        console.log(new Date());
        var messages = xhr.responseText.split('\n');
        console.log(messages);
        messages.slice(position, -1).forEach(function(value) {
            latest.textContent = value;
            var item = document.createElement('li');
            item.textContent = value;
            output.appendChild(item);
        });
        position = messages.length - 1;
    }

    var timer;
    timer = setInterval(function() {
        handleNewData();
        if (xhr.readyState == XMLHttpRequest.DONE) {
            clearInterval(timer);
            latest.textContent = 'Done';
        }
    }, 1000);
</script>

异常原因

  • WSGI服务器输出缓冲:Flask内置的Werkzeug服务器默认会缓冲响应内容,只有缓冲区满或响应结束时才会推送内容到客户端,导致前端无法实时接收。
  • 缺少禁用缓冲的响应头:部分反向代理(如Nginx)或浏览器会对流式响应做缓冲处理,未明确禁用时会延迟内容推送。
  • 前端轮询的局限性:setInterval固定间隔检查的方式,无法及时捕获新数据,效率也较低。

修复方法

1. 修改Flask后端,强制刷新并禁用缓冲

在生成流式响应时添加缓冲区刷新操作,同时设置响应头明确禁用各级缓冲:

from flask import Response, Flask, render_template
import sys
import time

app = Flask(__name__)

@app.route('/')
def main():
    return render_template('index2.html')

def generate_text_stream():
    for i in range(10):
        time.sleep(1)
        line = f"Line {i}\n"
        print(line)
        yield line
        # 强制刷新输出缓冲区,确保内容立即发送
        sys.stdout.flush()

@app.route('/stream')
def text_stream():
    # 设置响应头禁用各级缓冲
    headers = {
        'X-Accel-Buffering': 'no',  # 禁用反向代理缓冲
        'Cache-Control': 'no-cache',  # 禁用浏览器缓存
        'Transfer-Encoding': 'chunked'  # 明确使用分块传输编码
    }
    return Response(generate_text_stream(), mimetype='text/plain; charset=utf-8', headers=headers)

app.run(debug=False, threaded=True)  # 启用线程支持,避免请求阻塞

2. 优化前端,使用onprogress事件替代轮询

利用XMLHttpRequest的onprogress事件,在收到新数据时立即处理,比轮询更高效及时:

<p>This is the latest output: <span id="latest"></span></p>
<p>This is all the output:</p>
<ul id="output"></ul>
<script>
    var latest = document.getElementById('latest');
    var output = document.getElementById('output');
    var position = 0;

    var xhr = new XMLHttpRequest();
    xhr.open('GET', '/stream');
    xhr.responseType = 'text';

    // 收到新数据时触发处理逻辑
    xhr.onprogress = function() {
        handleNewData();
    };

    // 请求完成后收尾
    xhr.onload = function() {
        handleNewData();
        latest.textContent = 'Done';
    };

    xhr.send();

    function handleNewData() {
        var messages = xhr.responseText.split('\n');
        messages.slice(position, -1).forEach(function(value) {
            if (value) {  // 过滤空行
                latest.textContent = value;
                var item = document.createElement('li');
                item.textContent = value;
                output.appendChild(item);
            }
        });
        position = messages.length - 1;
    }
</script>

内容的提问来源于stack exchange,提问作者Hansen Zhao

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 16:27:49