如何实现服务器push-in-Flask框架?

2024-05-21 01:00:46 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图在Flask micro web框架上构建一个带有服务器推送功能的小站点,但是我不知道是否有一个框架可以直接使用。

我使用了Juggernaut,但在当前版本中,它似乎不能与redis-py一起使用,而且Juggernaut最近已经被弃用。

有人对我的案子有什么建议吗?


Tags: py功能版本服务器redis框架webflask
3条回答

看看Server-Sent Events。服务器发送的事件是 浏览器API,允许您保持打开服务器的套接字,订阅 更新流。有关更多信息,请阅读Alex MacCaw(作者 (魔术师)在why he kills juggernaut上的帖子以及为什么 在manny情况下,服务器发送的事件比 韦伯塞特。

协议很简单。只需将mimetypetext/event-stream添加到 回应。浏览器将保持连接打开并监听更新。事件 从服务器发送的是以data:开头的一行文本和以下换行符。

data: this is a simple message
<blank line>

如果您想交换结构化数据,只需将数据转储为json并通过网络发送json即可。

一个优点是你可以在烧瓶中使用SSE而不需要额外的 服务器。github上有一个简单的chat application example 使用redis作为发布/订阅后端。

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

你不需要用枪来操作 应用程序示例。运行应用程序时请确保使用线程,因为 否则,SSE连接将阻止您的开发服务器:

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

在客户端,您只需要一个Javascript处理函数,当一个新的 从服务器推送消息。

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

服务器发送的事件是最近的Firefox、Chrome和Safari浏览器发送的supported。 Internet Explorer尚不支持服务器发送的事件,但在 版本10。有两个推荐的polyfill来支持旧的浏览器

Redis是过度的:使用服务器端事件

派对迟到了(和往常一样),但IMHO使用Redis可能有点过头了。

只要在Python+Flask中工作,就可以考虑使用this excellent article by 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>

在烧瓶服务器中:

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

作为@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服务器来处理发布/订阅

相关问题 更多 >