首页 > 解决方案 > 如何在 Flask 网页中创建流?

问题描述

我正在运行一个机器人,我试图将机器人的日志作为 HTML 内容流输出到一个简单的网页(每个日志都以<p>{log}</p>. 如果我将流输出到路由“/log_stream”然后转到该路由,我可以看到日志并且它们会更新并且一切都按预期工作。但是,我不知道如何将该流合并到另一个网页中。我尝试使用<iframe>“/log_stream”路由作为 src 嵌入它,但是 iframe 根本不会渲染。知道如何进行这项工作吗?

注意:请不要将其标记为从 Flask 视图流式传输的显示数据的副本,因为它会更新那里的答案要么已过时,要么不正确。尽管您不能在模板在服务器上渲染后直接更新模板,但您绝对可以使用 iframe 或 img 在该模板中嵌入动态内容,就像在本教程中他使用图像动态创建视频流一样。不能动态更新模板本身与不能动态更新该模板中的内容不同。

应用程序.py:

from flask import Flask, render_template
from threading import Thread

from bot import Bot
from logger import Logger
from config import config

application = Flask(__name__)
logger = Logger()

@application.route('/')
def index():
    return render_template('index.html.jinja', products=config['targets'], status='running')

@application.route('/log_stream')
def log_stream():
    return logger.printerStream()

if __name__ == '__main__':
    bot = Bot(logger)
    botThread = Thread(target=bot.run)
    botThread.start()
    application.run(host='0.0.0.0', debug=True)

logger.py(相关部分):

def getLogHTML(self, logObj):
    if logObj['type'] == INFO:
        return "<p style=\"color:green\">"+logObj['text']+"</p>\n"
    if logObj['type'] == WARN:
        return "<p style=\"color:yellow\">"+logObj['text']+"</p>\n"
    if logObj['type'] == ERROR:
        return "<p style=\"color:red\">"+logObj['text']+"</p>\n"
    if logObj['type'] == EXCITE:
        return "<p style=\"color:blue\">"+logObj['text']+"</p>\n"
    return "<p style=\"color:white\">"+logObj['text']+"</p>\n"

def printerStream(self):
    self.isStreaming = True
    self.logs = self.getStoredLogs()
    self.logs.extend(self.secondaryLogs)
    self.storeLogs(self.secondaryLogs)
    self.secondaryLogs = deque()
    def generate():
        try:
            while True:
                if len(self.logsToStore) > 0:
                    self.storeLogs(self.logsToStore)
                    self.logsToStore = deque()
                nextLog = self.getNextLog()
                nextLogHTML = self.getLogHTML(nextLog)
                yield nextLogHTML
        except GeneratorExit:
            self.isStreaming = False
        self.isStreaming = False
    return Response(generate(), mimetype='text/html') # maybe text/html?

index.html.jinja:

<!doctype html>
<head>
<title>Title</title>
<style>
    table, th, td {
        border: 1px solid black;
        border-collapse: collapse;
    }
    body {
        color: green
    }
    .title {
        display: flex;
        flex-direction: row;
        justify-content:center
    }
    h1 {
        margin-bottom: 6px;
    }
    .row {
        display: flex;
    }
    .column {
        flex: 50%
    }
</style>
</head>
<body>
    <div class="title">
        <h1>Title</h1>
        <h2>Subtitle</h2>
    </div>
    <div class="row">
        <div class="column">
            </iframe src="{{ url_for('log_stream')}}">
        </div>
        <div class="column">
            <div class="row">
                <div class="column">
                    <p>Products: </p>
                </div>
                <div class="column">
                    {% for product in products %}
                        <p>{{product.name}}</p>
                    {% endfor %}
                </div>
            </div>
            <div class="row">
                <div class="column">
                    <p>Status: </p>
                </div>
                <div class="column">
                    <p>{{ status }}</p>
                </div>
            </div>
        </div>
    </div>
</body>

标签: pythonflaskiframejinja2streaming

解决方案


实际上,我通过向<iframe>. 将其更改为:

<iframe frameborder='0' noresize='noresize'
    style='position: absolute; background: transparent; width: 100%; height:100%;'
    src="{{ url_for('log_stream')}}"
    frameborder="0"></iframe>

几乎完成了我想要的!


推荐阅读