如何在Flask框架中实现服务器推送?

我试图build立一个小的网站与Flask的微型web框架上的服务器推送function,但我不知道是否有一个框架,直接使用。

我使用的是剑圣 ,但它似乎不能在当前版本中使用redis-py ,最近Juggernaut已被弃用。

有没有人有我的情况下的build议?

看一下Server-Sent Events 。 服务器发送的事件是一个浏览器API,可以让你保持打开一个套接字到你的服务器,订阅更新stream。 欲了解更多信息,请阅读Alex MacCaw(Juggernaut的作者)的文章, 为什么他杀死了主宰 ,为什么更简单的服务器发送的事件是曼尼的情况下比Websockets更好的工具。

协议非常简单。 只需将mimetype text/event-stream到您的响应。 浏览器将保持连接打开并侦听更新。 从服务器发送的事件是以data:开始的一行文本data:以及后面的换行符。

 data: this is a simple message <blank line> 

如果你想交换结构化数据,只需将你的数据转储为json,然后通过线路发送json。

一个好处是你可以在Flask中使用SSE而不需要额外的服务器。 github上有一个简单的聊天应用程序示例 ,它使用redis作为pub / sub后端。

 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('/post', methods=['POST']) def post(): message = flask.request.form['message'] user = flask.session.get('user', 'anonymous') now = datetime.datetime.now().replace(microsecond=0).time() red.publish('chat', u'[%s] %s: %s' % (now.isoformat(), user, message)) @app.route('/stream') def stream(): return flask.Response(event_stream(), mimetype="text/event-stream") 

您不需要使用gunicron来运行示例应用程序。 只要确保在运行应用程序时使用线程,否则SSE连接将阻塞您的开发服务器:

 if __name__ == '__main__': app.debug = True app.run(threaded=True) 

在客户端,您只需要一个Javascript处理程序函数,当从服务器推送新消息时将会调用它。

 var source = new EventSource('/stream'); source.onmessage = function (event) { alert(event.data); }; 

最近的Firefox,Chrome和Safari浏览器支持服务器发送的事件。 Internet Explorer尚不支持Server-Sent Events,但预计在版本10中支持它们。有两种推荐的Polyfills可支持较旧的浏览器

  • EventSource.js
  • jquery.eventsource

作为@ peter-hoffmann的回答的后续,我已经专门写了一个Flask扩展来处理服务器发送的事件。 它被称为Flask-SSE ,它在PyPI上可用 。 要安装它,运行:

 $ pip install flask-sse 

你可以像这样使用它:

 from flask import Flask from flask_sse import sse app = Flask(__name__) app.config["REDIS_URL"] = "redis://localhost" app.register_blueprint(sse, url_prefix='/stream') @app.route('/send') def send_message(): sse.publish({"message": "Hello!"}, type='greeting') return "Message sent!" 

而要连接到来自Javascript的事件stream,它的工作原理是这样的:

 var source = new EventSource("{{ url_for('sse.stream') }}"); source.addEventListener('greeting', function(event) { var data = JSON.parse(event.data); // do what you want with this data }, false); 

文档可在ReadTheDocs上find。 请注意,您将需要运行Redis服务器来处理pub / sub。

Interesting Posts