Frage

I have been playing around with sending server sent events with Flask and Tornado. I took a look at this blog article:

https://s-n.me/blog/2012/10/16/realtime-websites-with-flask/

I decided to try writing my own Flask app to send server sent events as an exercise. Here is the code for my Flask app called sse_server.py:

#! /usr/bin/python

from flask import Flask, request, Response, render_template

from tornado.wsgi import WSGIContainer
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop

app = Flask(__name__)

def event_stream():
  count = 0
  while True:
    print 'data: {0}\n\n'.format(count)
    yield 'data: {0}\n\n'.format(count)
    count += 1

@app.route('/my_event_source')
def sse_request():
  return Response(
          event_stream(),
          mimetype='text/event-stream')

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


if __name__ == '__main__':

  print "Please open a web browser to http://127.0.0.1:5000."

  # Spin up the app
  http_server = HTTPServer(WSGIContainer(app))
  http_server.listen(5000)
  IOLoop.instance().start()

In my templates folder, I have a simple index.html page:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>Test</title>

  <script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
  <script src="//code.jquery.com/jquery-migrate-1.2.1.min.js"></script>
  <script type="text/javascript" src="../static/sse_client.js"></script>

</head>
<body>
  <h3>Test</h3>

  <ul id="output">
  </ul>

</body>

</html>

In my static folder, I have a file called sse_client.js:

var queue = [];
var interval = setInterval(function(){addItem()}, 1000);

function addItem(){
  if(queue.length > 0){
    var item = queue[0];
    queue.shift();
    $('#output').append(item);
  }
}

$(document).ready(

  function() {

    var sse = new EventSource('/my_event_source');
    console.log('blah');

    sse.onmessage = function(event) {

      console.log('A message has arrived!');
      var list_item = '<li>' + event.data + '</li>';
      console.log(list_item);
      queue.push(list_item);
    };
})

Basically, my app's structure is

sse/
  sse_server.py
  static/
    sse_client.js
  templates/
    index.html

The app displays the index page, but the data is not getting streamed to it. I have no idea what I am doing wrong. I think I need another set of eyes on this. I'm sure it's something really minor and stupid.

War es hilfreich?

Lösung

Tornado's WSGIContainer does not support streaming responses from wsgi apps. You can either use Flask with a multi-threaded or greenlet-based wsgi server, or use Tornado's native RequestHandler interface, but not when you're combining Flask and Tornado with WSGIContainer.

Combining Flask and Tornado is usually not a good idea; see https://github.com/mitsuhiko/flask/issues/986

Andere Tipps

To use the url "../static/sse_client.js" you need your webserver or your Flask app to serve the static JavaScript file. From the Flask docs:

To generate URLs for static files, use the special 'static' endpoint name:

url_for('static', filename='style.css')

The file has to be stored on the filesystem as static/style.css.

Read more

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top