2012-09-01 84 views
37

我正在尝试使用Flask微web框架上的服务器推送功能来构建一个小型站点,但我不知道是否有框架可以直接使用。如何在Flask框架中实现服务器推送?

我用Juggernaut,但它似乎不适用于当前版本的redis-py,Juggernaut最近已被弃用。

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

+6

[这是上个月由Flask的首席开发人员Armin Ronacher撰写的相关文章。](http://lucumr.pocoo.org/2012/8/5/stateless-and-proud/) – dumbmatter

+0

相关:[Streaming数据与Python和烧瓶](http://stackoverflow.com/q/13386681/4279) – jfs

回答

75

看看Server-Sent Events。服务器发送的事件是一个 浏览器API,可让您保持打开一个套接字到您的服务器,订阅 更新流。欲了解更多信息,请阅读Alex MacCaw( Juggernaut的作者)发布在why he kills juggernaut上,以及为什么更简单的 服务器发送的事件在web服务器中比在 中更好。

协议非常简单。只需将mimetype text/event-stream添加到您的 响应中即可。浏览器将保持连接打开并监听更新。从服务器发送的事件 是一行以data:开头的文本和以下换行符。

data: this is a simple message 
<blank line> 

如果您想交换结构化数据,只需将您的数据转储为json并通过电线发送json即可。

一个优点是您可以在Flask中使用SSE,而不需要额外的 服务器。 github上有一个简单的chat application example,其中 使用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); 
}; 

服务器发送的事件最近的火狐,Chrome和Safari浏览器是supported。 的Internet Explorer尚不支持服务器发送的事件,但预计将支持他们在 10版有两个建议Polyfills支持旧的浏览器

+0

嗨@PeterSmith,我试过这种方法,但是,警报(event.data)永远不会出现。我运行我的Flask应用程序在端口8000和推入端口8001.所以我把“var source = new EventSource('http:// localhost:8001/push');” Flask应用程序有一个用户可以发布内容的页面。该帖子被所有其他用户广播和接收。你有什么想法? –

+0

为什么你在不同的端口上运行? SSE的一个原因是它在你的应用程序中通过普通的http运行。你是如何运行烧瓶应用程序的?通过开发服务器?你添加了threaded = True吗?你使用的是什么浏览器? –

+0

嗨@PeterHoffmann,我用Flask的龙卷风。是否有可能将应用程序实例和推送器实例放在龙卷风中?说不同的处理器?我还应该设置多线程吗? –

5

由于后续的@peter-hoffmann's answer,我已经写了一个Flask扩展来专门处理服务器发送的事件。它叫Flask-SSE,它是available on 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事件流,它的工作原理是这样的:

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); 

Documentation is available on ReadTheDocs.请注意,您需要运行Redis服务器来处理发布/订阅。