Python 如何关闭Flask中的服务器发送事件连接?
下面使用node.js给出了答案Python 如何关闭Flask中的服务器发送事件连接?,python,flask,server-sent-events,Python,Flask,Server Sent Events,下面使用node.js给出了答案 但是,如何在python Flask中执行相同的操作?这取决于应用程序的体系结构 让我向您展示一个示例(请参见下面的代码): Flask稳定地向Redis请求一条新消息(锁定操作),但当Flask看到流终止时(StopIteration,如果您不是Python新手),它会返回 def event_stream(): pubsub = red.pubsub() pubsub.subscribe('chat') for message in
但是,如何在python Flask中执行相同的操作?这取决于应用程序的体系结构 让我向您展示一个示例(请参见下面的代码): 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")
我也遇到了同样的问题,最终找到了以下解决方案
导入时间
从flask导入flask、响应、流_和_上下文
app=烧瓶(名称)
@app.route(“/stream”)
def stream():
def gen():
尝试:
i=0
尽管如此:
数据='这是第{}行'。格式(i)
打印(数据)
产量数据+'
'
i+=1
时间。睡眠(1)
除发电退出外:
打印('已关闭')
返回响应(流_与_上下文(gen()))
您可以通过向Redis订阅侦听器来启动该方法。您可以等待Redis'
listen()
方法返回vlaue,而不是time.sleep(1)
。您可以从Redis取消订阅,而不是print('closed')
。剩下的唯一问题是,GeneratorExit
异常仅在将收益率值发送到客户端时才会引发。因此,如果Redis'listen()
从未结束,那么您将永远不会发现连接已断开。请务必注意,您还需要关闭客户端上的连接,否则它将尝试在重试
超时后重新打开连接
这让我很困惑,直到我看到这里的帖子:
从链接:
这里的问题是服务器意外地关闭了连接,而不是在保持连接打开的同时执行其工作。发生这种情况时,客户端会重新发送请求以打开连接并启动流媒体服务器发送的事件。然后服务器一次又一次地关闭连接,导致无限循环
在我看到这个之后。。我的首选解决方案是通过生成预期的数据消息来关闭与服务器的连接
在客户端(浏览器)
var sse=neweventsource('/sse');
sse.addEventListener(“消息”,函数(e){
控制台日志(e);
var数据=e.data;
如果(!数据){
console.log(“事件中没有数据”);
返回;
}
如果(数据=='finished'){
console.log('关闭连接')
sse.close()
}
//我在这里的工作是基于信息的
});
我的烧瓶服务器
来自flask导入响应的
@应用程序api.路线(“/sse”)
def stream():
def trackerStream():
已完成=检查是否已完成()
未完成时:
睡眠(1)#轮询超时
如果应发送事件():
产生f“数据:{mydata()}\n\n”
其他:
产生“数据:nodata\n\n”
已完成=检查是否已完成()
产生“数据:已完成\n\n”
返回响应(trackerStream(),mimetype=“文本/事件流”)
注意:确保始终以一定的间隔将事件从服务器发送到客户端。如果用户关闭浏览器,flask将在尝试写入套接字时出错,并为您关闭流。如果不在某个时间间隔向客户端写入数据,即使只是写入
数据:nodata\n\n
,服务器也可能陷入循环 《烧瓶》的作者似乎还没有计划支持这一点。对于“服务器发送的事件”,最好使用事件驱动的体系结构,如NodeJS。对于类似的问题也很有帮助什么是i\u应该\u关闭\u连接
?你能再解释一下吗?这是一个布尔值。您可以像在Python中一样使用if
语句。如果没有发布任何内容并且客户端断开连接,服务器将永远挂起。我遇到了这个问题。是的,这是一个阻塞呼叫。您可能希望使用stdlib中的超时,并使用pubsub.close()
关闭连接。它应该可以工作,但我没有检查。我花了一段时间才意识到,在浏览器关闭后,服务器可能会保持连接打开一段时间。(在我的例子中,服务器只在大约150秒后关闭了连接。)重点是,它确实可以工作!:)这是非常有用的!我很惭愧地说,为了避免重新打开连接,我导致了服务器生成的XSS重定向负载在输出完成后将浏览器返回主页。在我看到这个答案之前,这是我唯一能想出的摆脱循环的办法。非常有用。
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")
import time
from flask import Flask, Response, stream_with_context
app = Flask(__name__)
@app.route('/stream')
def stream():
def gen():
try:
i = 0
while True:
data = 'this is line {}'.format(i)
print(data)
yield data + '<br>'
i += 1
time.sleep(1)
except GeneratorExit:
print('closed')
return Response(stream_with_context(gen()))