web-dev-qa-db-ja.com

サーバープッシュインを実装する方法Flaskフレームワーク?

Flask= micro-web frameworkでサーバープッシュ機能を使用して小さなサイトを構築しようとしていますが、直接動作するフレームワークがあるかどうかは知りませんでした。

Juggernaut を使用しましたが、現在のバージョンでは redis-py で動作していないようで、Juggernautは最近廃止されました。

誰かが私のケースについて提案をしますか?

46
little-eyes

Server-Sent Events をご覧ください。サーバー送信イベントは、サーバーのソケットを開いたままにして、更新ストリームをサブスクライブできるブラウザーAPIです。詳細については、Alex MacCaw(Juggernautの著者)の投稿をお読みください なぜjuggernautを殺したのか と、なぜWebSocketsよりも単純なServer-Sent Eventsが多くの場合、仕事に適したツールであるか。

プロトコルは本当に簡単です。 mimetype text/event-streamを応答に追加するだけです。ブラウザは接続を開いたままにし、更新をリッスンします。サーバーから送信されるイベントは、data:で始まるテキスト行とそれに続く改行です。

data: this is a simple message
<blank line>

構造化されたデータを交換する場合は、データをjsonとしてダンプし、jsonを送信します。

利点は、SSE in Flaskで追加のサーバーを必要とせずに使用できることです。単純な チャットアプリケーションの例 pub/subバックエンドとしてredisを使用するgithubで。

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 __== '__main__':
    app.debug = True
    app.run(threaded=True)

クライアント側では、新しいメッセージがサーバーからプッシュされたときに呼び出されるJavascriptハンドラー関数が必要です。

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

サーバー送信イベントは サポート 最近のFirefoxでChromeおよびSafariブラウザー。InternetExplorerはサーバー送信イベントをまだサポートしていませんが、バージョンでサポートする予定です10.古いブラウザーをサポートするために推奨される2つのポリフィルがあります

90
Peter Hoffmann

@ peter-hoffmann's answer のフォローアップとして、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からイベントストリームに接続するには、次のように機能します。

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で入手できます。 pub/subを処理するには、実行中の Redis サーバーが必要であることに注意してください。

11
singingwolfboy

Redisは過剰です:サーバー側イベントを使用します

パーティーに遅れて(通常どおり)、Redisを使用したIMHOはやり過ぎかもしれません。

Python + Flaskで作業している限り、 Panisuan Joe Chasingaによるこの優れた記事 で説明されているジェネレーター関数の使用を検討してください。その要点は次のとおりです。

クライアントのindex.html

var targetContainer = document.getElementById("target_div");
var eventSource = new EventSource("/stream")
  eventSource.onmessage = function(e) {
  targetContainer.innerHTML = e.data;
};
...
<div id="target_div">Watch this space...</div>

Flaskサーバー:

def get_message():
    '''this could be any function that blocks until data is ready'''
    time.sleep(1.0)
    s = time.ctime(time.time())
    return s

@app.route('/')
def root():
    return render_template('index.html')

@app.route('/stream')
def stream():
    def eventStream():
        while True:
            # wait for source data to be available, then Push it
            yield 'data: {}\n\n'.format(get_message())
    return Response(eventStream(), mimetype="text/event-stream")
10
fearless_fool