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

Flask动态生成Zip文件后无法触发下载问题求助

Flask动态生成Zip后无法触发下载的问题解决

问题描述

我尝试动态生成Zip文件,发送给用户后从服务器删除,目前编写了如下代码:

@app.route('/download', methods=['GET'])
def download():
    shutil.make_archive('files', 'zip', dir_path+'/FILES')
    while not os.path.exists(dir_path+"/files.zip"):
        time.sleep(1)

    file_path = dir_path + "/files.zip"
    
    cache = tempfile.NamedTemporaryFile()
    with open(file_path, 'rb') as fp:
        shutil.copyfileobj(fp, cache)
        cache.flush()
    cache.seek(0)
    os.remove(file_path)
    return send_file(cache, as_attachment=True, mimetype='application/zip', download_name='data.zip')

所有操作均显示正常,响应状态码为200,但始终无法触发文件下载提示。当前使用Flask内置开发服务器,请问是否遗漏了某些配置或细节?

问题原因

  1. 临时文件生命周期问题:默认的tempfile.NamedTemporaryFile()会在文件对象被关闭后自动删除。Flask的send_file是异步输出内容的,视图函数返回后,cache对象会被垃圾回收机制关闭,导致文件内容已不存在,浏览器无法获取完整数据,因此不会触发下载。
  2. 多余的等待逻辑:shutil.make_archive是同步执行的函数,执行完成后Zip文件已经生成,你写的while循环完全没必要。

修复方案

方案一:修正临时文件处理逻辑

创建临时文件时设置delete=False避免自动删除,发送完成后手动清理临时文件:

import os
import shutil
import tempfile
from flask import send_file

@app.route('/download', methods=['GET'])
def download():
    # 直接指定Zip输出路径,同步生成文件
    zip_path = os.path.join(dir_path, 'files.zip')
    shutil.make_archive(os.path.splitext(zip_path)[0], 'zip', os.path.join(dir_path, 'FILES'))

    # 创建不自动删除的临时文件
    with tempfile.NamedTemporaryFile(delete=False) as cache:
        with open(zip_path, 'rb') as fp:
            shutil.copyfileobj(fp, cache)
    
    # 删除服务器上的原始Zip文件
    os.remove(zip_path)

    # 发送文件并确保临时文件被清理
    try:
        return send_file(
            cache.name,
            as_attachment=True,
            mimetype='application/zip',
            download_name='data.zip'
        )
    finally:
        os.unlink(cache.name)

方案二:内存中生成Zip(更高效)

直接在内存中构建Zip文件,完全避免服务器上的物理文件操作:

import io
import os
import zipfile
from flask import send_file

@app.route('/download', methods=['GET'])
def download():
    memory_file = io.BytesIO()
    # 在内存中创建Zip文件
    with zipfile.ZipFile(memory_file, 'w', zipfile.ZIP_DEFLATED) as zf:
        files_dir = os.path.join(dir_path, 'FILES')
        # 遍历目标目录,添加所有文件到Zip
        for root, _, files in os.walk(files_dir):
            for file in files:
                file_path = os.path.join(root, file)
                # 用相对路径作为Zip内的文件名,避免暴露服务器路径
                arcname = os.path.relpath(file_path, files_dir)
                zf.write(file_path, arcname)
    # 重置文件指针到开头
    memory_file.seek(0)
    
    return send_file(
        memory_file,
        as_attachment=True,
        mimetype='application/zip',
        download_name='data.zip'
    )

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 16:52:34