Flask 和 Tornado 的服务器发送事件

2 投票
2 回答
3440 浏览
提问于 2025-04-18 03:50

我最近在用Flask和Tornado玩服务器推送事件。看了这篇博客文章:

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

于是我决定写一个自己的Flask应用,来练习发送服务器推送事件。以下是我这个Flask应用的代码,叫做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()

在我的模板文件夹里,有一个简单的index.html页面:

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

在我的静态文件夹里,有一个叫做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);
    };
})

基本上,我的应用结构是这样的:

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

这个应用会显示index页面,但数据没有被推送到页面上。我不知道哪里出错了。我觉得需要别人帮我看看。我相信这一定是个很小的问题,可能是我没注意到的。

2 个回答

0

要使用这个网址 "../static/sse_client.js",你需要让你的网页服务器或者Flask应用能够提供这个静态的JavaScript文件。根据Flask的文档:

要生成静态文件的链接,可以使用一个特别的叫做'static'的端点名称:

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

这个文件必须保存在你的文件系统中,路径是static/style.css。

了解更多

4

Tornado的WSGIContainer不支持从wsgi应用程序中进行流式响应。你可以选择使用Flask配合多线程或基于greenlet的wsgi服务器,或者使用Tornado自带的RequestHandler接口,但如果你把Flask和Tornado与WSGIContainer结合使用,就不行了。

把Flask和Tornado结合在一起通常不是个好主意;可以参考一下这个链接:https://github.com/mitsuhiko/flask/issues/986

撰写回答