如何使用Flask和JavaScript实现网页实时展示日志文件变更
Flask实现日志实时更新的问题修复方案
现有代码核心问题
- Flask默认开启响应缓冲,yield的内容会被缓存到一定大小才推送给前端,无法实时输出
- Debug模式默认开启的重载器会启动双进程,导致生成器逻辑重复执行,流输出异常
- 前端XHR直接全量替换文本内容,日志量大时性能差,也没有针对流式响应做增量读取
- 部分文本编辑器修改日志文件时会直接替换原文件而非追加写入,导致原有打开的文件句柄读取不到新内容
修复后的代码
后端Flask代码
import time import os from flask import Flask, render_template app = Flask(__name__) @app.route('/') def index(): return render_template('index.html') @app.route('/logs') def logs(): def generate(): # 用绝对路径定位日志文件,避免运行目录不同导致找不到文件 log_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "log.log") with open(log_path, "r", encoding="utf-8") as f: # 如果需要模拟标准tail -f效果,默认不展示历史日志,直接从末尾读新增内容,可取消下一行注释 # f.seek(0, os.SEEK_END) while True: line = f.readline() if not line: time.sleep(0.1) continue yield line # 核心配置:添加响应头关闭所有缓存,强制流式输出 headers = { "Cache-Control": "no-cache, no-store, must-revalidate", "Pragma": "no-cache", "Expires": "0", "X-Accel-Buffering": "no" } return app.response_class(generate(), mimetype="text/plain", headers=headers) if __name__ == "__main__": # 关闭重载器避免双进程冲突,保留debug的报错提示能力 app.run(debug=True, use_reloader=False)
前端模板代码
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Logs</title> </head> <body> <p>LOGS</p> <pre id="output" style="max-height: 80vh; overflow-y: auto;"></pre> <script> const output = document.getElementById('output'); // 用Fetch API流式读取响应,只追加新增内容,性能更高 fetch('{{ url_for('logs') }}') .then(response => { const reader = response.body.getReader(); const decoder = new TextDecoder(); function processChunk({ done, value }) { if (done) return; // 追加新内容而非全量替换 output.textContent += decoder.decode(value); // 自动滚动到日志底部 output.scrollTop = output.scrollHeight; return reader.read().then(processChunk); } return reader.read().then(processChunk); }); </script> </body> </html>
测试注意事项
- 测试日志更新时建议用追加写入的方式修改文件,比如执行命令
echo "新日志内容" >> log.log,避免用部分编辑器直接保存(部分编辑器会生成新文件替换原文件,导致原有文件句柄失效) - 如果需要限制初始加载的历史日志大小,可以在生成器中添加逻辑,初始时只读取日志最后10行,避免大日志首次加载过慢
内容的提问来源于stack exchange,提问作者Glen Veigas
相关产品推荐
相关产品推荐

