为什么我的生成器阻止Flask发送SSE响应?

2 投票
1 回答
2443 浏览
提问于 2025-04-17 21:10

我正在尝试用Flask来处理SSE请求,但我的客户端只有在我的生成器函数停止或者连接关闭后才收到事件。

这是我能做出的最简单的示例,来展示这个问题:

#!/usr/bin/env python

from flask import Flask, Response
from time import sleep

def stream():
    n = 10
    while n > 0:
        yield "data: hi\n\n"
        sleep(0.5)
        n = n - 1

app = Flask(__name__)

@app.route("/events")
def streamSessionEvents():
    return Response(
        stream(),
        mimetype="text/event-stream"
    )

app.run(debug=True, threaded=True)

这是我的测试客户端:

<!doctype html>
<html>
<head>
    <script>
        var source = new EventSource(
            "/events"
        );
        source.onmessage = function(event)
        {
            console.log(event);
        };
    </script>
</head>
<body>
</body>
</html>

这个stream()生成器会产生十个事件,然后返回(我故意这样做是为了展示问题,理想情况下,生成器应该一直运行下去),到那时连接就断开了。客户端页面在这之前什么都不记录,直到这个时刻,它才会一次性显示出所有十个事件(如果我在stream()中没有计数器变量,那么页面就永远不会收到任何事件)。

我对Python和Flask的使用不多,这让我很困惑,我看不出自己和网上其他例子有什么不同。非常感谢任何帮助。

1 个回答

2

这里有两个可能会影响你的情况:

  1. 你把 debug 设置成了 True,这会安装一些中间件(特别是 Werkzeug 调试器),可能会导致数据流传输出现问题。

    根据 Flask 的流传输文档

    需要注意的是,一些 WSGI 中间件可能会破坏流传输,所以在调试环境中使用分析工具和其他你可能启用的功能时要小心。

    不过,我在测试代码时使用 curl 或 Chrome,搭配 Flask 0.10.1 和 Werkzeug 0.9.4,发现 data: hi 的响应可以正常流传输,不管 debug 的设置如何。换句话说,你的代码在最新版本的 Flask 堆栈中是正常工作的。

  2. EventSource 流受到 同源策略 的限制。如果你不是从同一个主机和端口加载 HTML 页面,Flask 服务器的请求会被拒绝。

    在 Flask 服务器的一个单独路由中添加测试页面的源代码对我来说是有效的:

    @app.route('/')
    def index():
        return '''\
    <!doctype html>
    <html>
    <head>
        <script>
            var source = new EventSource(
                "/events"
            );
            source.onmessage = function(event)
            {
                console.log(event);
            };
        </script>
    </head>
    <body>
    </body>
    </html>
    '''
    

撰写回答