You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flask中如何基于流实现send_file与模板渲染共存?

解决方案:Flask中基于流实现文件下载同时加载页面

因为HTTP协议规定单次请求只能返回一个响应,所以无法在同一个return里同时返回文件流和页面模板。要实现加载页面的同时触发流文件下载,可以通过拆分请求的方式实现,以下是具体方案:

核心思路

将文件处理、页面渲染、文件下载拆分为两次请求:

  1. 第一次POST请求:处理上传的文件,生成处理后的文档流并临时缓存,返回页面模板。
  2. 第二次GET请求:页面加载完成后,通过前端JS自动发起下载请求,从缓存中取出文档流返回给用户。

代码实现

Flask后端代码

import io
import uuid
from flask import Flask, request, render_template, send_file, session
import aw

app = Flask(__name__)
app.secret_key = 'your_secure_secret_key'
# 临时缓存文档流,生产环境建议用Redis替代内存字典,同时添加过期清理机制
document_cache = {}

@app.route('/', methods=['GET','POST'])
def homes():
    if request.method == 'POST':
        # 读取上传的文件
        document = request.files['test']
        stream = io.BytesIO(document.read())
        doc = aw.Document(stream)
        
        # 执行文档操作(替换为你的业务逻辑)
        # doc.do_something()
        
        # 将处理后的文档写入BytesIO
        output_stream = io.BytesIO()
        doc.save(output_stream)
        output_stream.seek(0)  # 将指针移到流开头
        
        # 生成唯一标识,用于后续下载请求
        doc_id = str(uuid.uuid4())
        document_cache[doc_id] = output_stream
        session['doc_id'] = doc_id
        
        # 返回页面,标记需要触发下载
        return render_template("index.html", trigger_download=True)
    
    # GET请求直接返回页面
    return render_template("index.html", trigger_download=False)

@app.route('/download-document')
def download_document():
    doc_id = session.get('doc_id')
    if not doc_id or doc_id not in document_cache:
        return "文档不存在或已过期", 404
    
    # 取出缓存的流并删除,避免内存占用
    output_stream = document_cache.pop(doc_id)
    return send_file(
        output_stream,
        as_attachment=True,
        download_name='test.docx',
        mimetype='application/vnd.openxmlformats-officedocument.wordprocessingml.document'
    )

前端模板(index.html)

在页面中添加JS逻辑,当需要下载时自动触发下载请求:

<!DOCTYPE html>
<html>
<head>
    <title>文档处理工具</title>
</head>
<body>
    <form method="POST" enctype="multipart/form-data">
        <input type="file" name="test" accept=".docx" required>
        <button type="submit">上传并处理</button>
    </form>

    {% if trigger_download %}
    <script>
        // 页面加载后自动触发下载,不刷新当前页面
        window.onload = function() {
            const iframe = document.createElement('iframe');
            iframe.style.display = 'none';
            iframe.src = "{{ url_for('download_document') }}";
            document.body.appendChild(iframe);
        };
    </script>
    {% endif %}
</body>
</html>

注意事项

  • 缓存机制:示例中用内存字典缓存文档流,仅适合开发或低并发场景。生产环境建议使用Redis等分布式缓存,并设置过期时间,避免内存泄漏。
  • 大文件处理:如果处理的文档较大,不建议用内存缓存,可临时写入服务器磁盘(处理完成后删除),或直接在前端触发下载时实时生成流(但会增加服务器压力)。
  • session安全:确保设置了安全的secret_key,避免session被篡改。

内容的提问来源于stack exchange,提问作者Finntech

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 08:18:36