2012-09-01 37 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服務器來處理髮布/訂閱。

相關問題