如何在Flask中关闭Server-Send Events连接?

hll*_*lau 8 python flask server-sent-events

下面给出了一个使用node.js的答案.

如何关闭服务器上的"服务器发送事件"连接?

但是,如何在python Flask中做同样的事情?

Nic*_*ady 9

需要注意的是,您还需要关闭客户端上的连接,否则它将在超时后尝试重新打开连接retry

这让我很困惑,直到我在这里看到这篇文章:/sf/answers/2676465291/

从链接:

这里的问题是服务器意外地关闭了连接,而不是在保持连接打开的情况下完成其工作。发生这种情况时,客户端重新发送请求以打开连接并开始流式传输服务器发送的事件。然后服务器一次又一次地关闭连接,导致无限循环。

在我看到这个之后..我的首选解决方案是通过生成预期的数据消息来关闭与服务器的连接。

在客户端(浏览器)

var sse = new EventSource('/sse');
sse.addEventListener('message', function(e) {
  console.log(e);
  var data = e.data;
  if (!data) {
      console.log('no data in event');
      return;
  }
  if (data === 'finished') {
      console.log('closing connection')
      sse.close()
  }
  // my work here based on message
});
Run Code Online (Sandbox Code Playgroud)

我的 Flask 服务器

from flask import Response

@app_api.route("/sse")
def stream():
    def trackerStream():
        finished = check_if_finished()
        while not finished:
            sleep(1) # poll timeout
            if should_send_event():
                yield f"data: {mydata()}\n\n"
            else:
                yield "data: nodata\n\n"

            finished = check_if_finished()

        yield "data: finished\n\n"

    return Response(trackerStream(), mimetype="text/event-stream")
Run Code Online (Sandbox Code Playgroud)

注意:确保始终以一定的时间间隔从服务器向客户端发送事件。如果用户关闭浏览器,flask 在尝试写入套接字时会收到错误,并会为您关闭流。如果您没有在某个时间间隔写入客户端,即使您只是写入data: nodata\n\n,那么服务器可能会陷入循环。


gio*_*ioi 5

嗯,这取决于您的应用程序的架构。

让我向您展示一个示例(请参阅https://github.com/jkbr/chat/blob/master/app.py 上的此代码):

def event_stream():
    pubsub = red.pubsub()
    pubsub.subscribe('chat')
    for message in pubsub.listen():
        print message
        yield 'data: %s\n\n' % message['data']

@app.route('/stream')
def stream():
    return flask.Response(event_stream(),
                          mimetype="text/event-stream")
Run Code Online (Sandbox Code Playgroud)

Flask 稳定地向 Redis 请求一条新消息(锁定操作),但是当 Flask 看到流终止时(StopIteration如果你不熟悉 Python),它就会返回。

def event_stream():
    pubsub = red.pubsub()
    pubsub.subscribe('chat')
    for message in pubsub.listen():
        if i_should_close_the_connection:
            break
        yield 'data: %s\n\n' % message['data']

@app.route('/stream')
def stream():
    return flask.Response(event_stream(),
                          mimetype="text/event-stream")
Run Code Online (Sandbox Code Playgroud)

  • 什么是“i_should_close_the_connection”?您能再解释一下吗? (2认同)