我有一个生成数据并实时流式传输的视图。我不知道如何将数据发送到可以在HTML模板中使用的变量。我当前的解决方案只是在到达数据时将数据输出到空白页,这是可行的,但是我想将其包含在具有格式化功能的较大页面中。在流式传输到页面时如何更新,格式化和显示数据?
import flask import time, math app = flask.Flask(__name__) @app.route('/') def index(): def inner(): # simulate a long process to watch for i in range(500): j = math.sqrt(i) time.sleep(1) # this value should be inserted into an HTML template yield str(i) + '<br/>\n' return flask.Response(inner(), mimetype='text/html') app.run(debug=True)
你可以流式传输响应中的数据,但是不能按照描述的方式动态更新模板。模板在服务器端只渲染一次,然后发送到客户端。你需要使用JavaScript读取流式响应并在客户端输出数据。
用于XMLHttpRequest向要发送数据的端点发出请求。然后定期从流中读取直到完成。
XMLHttpRequest
此示例假定一种非常简单的消息格式:一行数据,然后是换行符。当然,只要有一种识别每条消息的方法,解析就可能变得很复杂。例如,你可以返回一个JSON对象并在客户端上对其进行解码。
from time import sleep from flask import Flask, render_template from math import sqrt app = Flask(__name__) @app.route('/') def index(): # render the template (below) that will use JavaScript to read the stream return render_template('index.html') @app.route('/stream_sqrt') def stream(): def generate(): for i in range(500): yield '{}\n'.format(sqrt(i)) sleep(1) return app.response_class(generate(), mimetype='text/plain') app.run()
<p>This is the latest output: <span id="latest"></span></p> <p>This is all the output:</p> <ul id="output"></ul> <script> var latest = document.getElementById('latest'); var output = document.getElementById('output'); var xhr = new XMLHttpRequest(); xhr.open('GET', '{{ url_for('stream') }}'); xhr.send(); var position = 0; function handleNewData() { // the response text include the entire response so far // split the messages, then take the messages that haven't been handled yet // position tracks how many messages have been handled // messages end with a newline, so split will always show one extra empty message at the end var messages = xhr.responseText.split('\n'); messages.slice(position, -1).forEach(function(value) { latest.textContent = value; // update the latest value in place // build and append a new item to a list to log all output var item = document.createElement('li'); item.textContent = value; output.appendChild(item); }); position = messages.length - 1; } var timer; timer = setInterval(function() { // check the response for new data handleNewData(); // stop checking once the response has ended if (xhr.readyState == XMLHttpRequest.DONE) { clearInterval(timer); latest.textContent = 'Done'; } }, 1000); </script>