Comment mettre en œuvre server push dans Flask framework?

j'essaie de construire un petit site avec la fonctionnalité push server sur Flask micro-web framework, mais je ne savais pas s'il y avait un framework avec lequel travailler directement.

j'ai utilisé Mastodonte, mais il semble ne pas fonctionner avec redis-py dans la version actuelle, et Juggernaut a été déprécié récemment.

est-ce que quelqu'un a une suggestion avec mon cas?

39
demandé sur nalzok 2012-09-02 03:42:35

3 réponses

regardez Server-Sent Events. Events envoyés par un serveur est un API de navigateur qui vous permet de garder ouverte une socket à votre serveur, flux des mises à jour. Pour plus d'informations, lire Alex MacCaw (auteur de Juggernaut) post on pourquoi il tue mastodonte et pourquoi le plus simple Les événements envoyés par le serveur sont dans de nombreux cas le meilleur outil pour le travail que Les Websockets.

Le protocole est vraiment facile. Il suffit d'ajouter le type mime text/event-stream pour votre réponse. Le le navigateur gardera la connexion ouverte et écoutera les mises à jour. événement envoyé depuis le serveur est une ligne de texte commençant par data: et une nouvelle ligne.

data: this is a simple message
<blank line>

si vous souhaitez échanger des données structurées, il vous suffit de déposer vos données sous forme de json et d'envoyer le json par télégramme.

un avantage est que vous pouvez utiliser SSE dans flasque sans avoir besoin d'un supplément Serveur. Il y a un simple application de chat en exemple sur github qui utilise redis comme backend 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")

Vous n'avez pas besoin d'utiliser gunicron pour exécuter le exemple d'application. Juste assurez-vous d'utiliser le filetage lors de l'exécution de l'application, car sinon l'ESS connexion bloquer votre serveur de développement:

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

côté client, vous avez juste besoin D'une fonction Javascript handler qui sera appelée quand un nouveau le message est poussé du serveur.

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

les événements envoyés par le serveur sont prise en charge par récent Firefox, Chrome et Safari navigateur. Internet Explorer ne prend pas encore en charge les événements envoyés par le serveur, mais devrait les prendre en charge dans Version 10. Il existe deux Polyfills recommandés pour prendre en charge les navigateurs plus anciens

81
répondu Peter Hoffmann 2016-05-19 02:45:04

suivi de @pierre-hoffmann réponse, j'ai écrit une extension Flask spécifiquement pour gérer les événements envoyés par le serveur. Il est appelé Flacon-ESS et disponible sur PyPI. Pour l'installer, exécuter:

$ pip install flask-sse

Vous pouvez l'utiliser comme ceci:

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!"

Et pour se connecter au flux d'événements à partir de Javascript, il fonctionne comme ceci:

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

la Documentation est disponible sur ReadTheDocs. Notez que vous aurez besoin d'un exécutant Redis serveur pour gérer pub/sub.

9
répondu singingwolfboy 2016-04-19 12:36:20

tard à la fête (comme d'habitude), mais IMHO en utilisant Redis peut être exagéré.

tant que vous travaillez en Python + flasque, envisagez d'utiliser les fonctions de générateur décrites dans cet excellent article de Panisuan Joe Chasinga. L'essentiel, c'est:

dans votre index des clients.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>

Dans votre Flacon serveur:

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")
0
répondu fearless_fool 2018-08-22 14:44:12