<p>要替换页面上的现有内容,您可能需要javascript,也就是说,您可以发送它或让它为您发出请求,使用长轮询、websockets等。有很多方法可以做到这一点,下面是使用<a href="http://dev.w3.org/html5/eventsource/" rel="noreferrer">server send events</a>:</p>
<pre class="lang-py prettyprint-override"><code>#!/usr/bin/env python
import itertools
import time
from flask import Flask, Response, redirect, request, url_for
app = Flask(__name__)
@app.route('/')
def index():
if request.headers.get('accept') == 'text/event-stream':
def events():
for i, c in enumerate(itertools.cycle('\|/-')):
yield "data: %s %d\n\n" % (c, i)
time.sleep(.1) # an artificial delay
return Response(events(), content_type='text/event-stream')
return redirect(url_for('static', filename='index.html'))
if __name__ == "__main__":
app.run(host='localhost', port=23423)
</code></pre>
<p>其中<code>static/index.html</code>:</p>
<pre class="lang-html prettyprint-override"><code><!doctype html>
<title>Server Send Events Demo</title>
<style>
#data {
text-align: center;
}
</style>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>
if (!!window.EventSource) {
var source = new EventSource('/');
source.onmessage = function(e) {
$("#data").text(e.data);
}
}
</script>
<div id="data">nothing received yet</div>
</code></pre>
<p>默认情况下,如果连接丢失,浏览器将在3秒内重新连接。如果没有更多要发送的内容,服务器可以返回404,或者只发送一些<code>'text/event-stream'</code>内容类型来响应下一个请求。要在客户端停止,即使服务器有更多数据,也可以调用<code>source.close()</code>。</p>
<p>注意:如果流不是无限的,那么使用其他技术(不是SSE),例如发送javascript片段来替换文本(无限<code><iframe></code>技术):</p>
<pre class="lang-py prettyprint-override"><code>#!/usr/bin/env python
import time
from flask import Flask, Response
app = Flask(__name__)
@app.route('/')
def index():
def g():
yield """<!doctype html>
<title>Send javascript snippets demo</title>
<style>
#data {
text-align: center;
}
</style>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<div id="data">nothing received yet</div>
"""
for i, c in enumerate("hello"):
yield """
<script>
$("#data").text("{i} {c}")
</script>
""".format(i=i, c=c)
time.sleep(1) # an artificial delay
return Response(g())
if __name__ == "__main__":
app.run(host='localhost', port=23423)
</code></pre>
<p>我在这里内联了html,以显示它没有更多的功能(没有魔力)。这里与上面相同,但使用模板:</p>
<pre class="lang-py prettyprint-override"><code>#!/usr/bin/env python
import time
from flask import Flask, Response
app = Flask(__name__)
def stream_template(template_name, **context):
# http://flask.pocoo.org/docs/patterns/streaming/#streaming-from-templates
app.update_template_context(context)
t = app.jinja_env.get_template(template_name)
rv = t.stream(context)
# uncomment if you don't need immediate reaction
##rv.enable_buffering(5)
return rv
@app.route('/')
def index():
def g():
for i, c in enumerate("hello"*10):
time.sleep(.1) # an artificial delay
yield i, c
return Response(stream_template('index.html', data=g()))
if __name__ == "__main__":
app.run(host='localhost', port=23423)
</code></pre>
<p>其中<code>templates/index.html</code>:</p>
<pre class="lang-html prettyprint-override"><code><!doctype html>
<title>Send javascript with template demo</title>
<style>
#data {
text-align: center;
}
</style>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<div id="data">nothing received yet</div>
{% for i, c in data: %}
<script>
$("#data").text("{{ i }} {{ c }}")
</script>
{% endfor %}
</code></pre>