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

Flask中send_file与send_from_directory无文件返回问题求助

问题排查与解决方案

1. 文件未完全写入磁盘就被读取

你的代码未使用with语句管理MailMerge实例,可能导致生成的docx文件还没完全写入磁盘就被Flask尝试发送,最终返回空内容。修改为:

def generate_doc(dn, dd, pa, cr, ir):
    # 使用with自动关闭文件句柄,确保写入完成
    with MailMerge('temp.docx') as document:
        document.merge(
            DN=dn,
            DD=dd,
            PA=pa,
            CU=cr)
        file = 'output.docx'
        document.write(file)
    
    # 后续发送逻辑

2. MIME类型错误导致浏览器无法识别

docx文件的正确MIME类型是application/vnd.openxmlformats-officedocument.wordprocessingml.document,而非旧版.doc文件的application/msword。错误的MIME类型会让浏览器无法触发下载行为,修改发送代码:

return send_from_directory(
    directory=cwd, 
    filename="output.docx", 
    as_attachment=True, 
    cache_timeout=0,
    mimetype='application/vnd.openxmlformats-officedocument.wordprocessingml.document'
)

3. 依赖当前工作目录不可靠

os.getcwd()返回的是进程启动目录,可能和Flask应用的实际根目录不一致。改用Flask内置的app.root_path定位文件更可靠:

from flask import Flask
app = Flask(__name__)

# 在函数中使用
file_path = os.path.join(app.root_path, 'output.docx')

4. BytesIO模式需重置文件指针(针对你注释的代码)

如果用内存中的BytesIO发送文件,必须在写入后将指针重置到开头,否则send_file会从文件末尾读取空内容:

from io import BytesIO

def generate_doc(dn, dd, pa, cr, ir):
    with MailMerge('temp.docx') as document:
        document.merge(DN=dn, DD=dd, PA=pa, CU=cr)
        f = BytesIO()
        document.write(f)
        f.seek(0)  # 重置指针到文件开头
        return send_file(
            f,
            mimetype='application/vnd.openxmlformats-officedocument.wordprocessingml.document',
            as_attachment=True,
            download_name='output.docx'
        )

5. 前端AJAX请求需手动触发下载

如果你的请求是通过AJAX发送的,浏览器不会自动触发下载,需要在前端处理Blob并手动触发:

fetch('/generate-doc', { method: 'POST', body: formData })
  .then(res => res.blob())
  .then(blob => {
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = 'output.docx';
    a.click();
    URL.revokeObjectURL(url);
  });

完整修正示例代码

from flask import Flask, send_from_directory, make_response, send_file
from mailmerge import MailMerge
import os
from io import BytesIO

app = Flask(__name__)

def generate_doc(dn, dd, pa, cr, ir):
    try:
        # 方式一:写入磁盘后发送
        with MailMerge('temp.docx') as document:
            document.merge(DN=dn, DD=dd, PA=pa, CU=cr)
            file_name = 'output.docx'
            file_path = os.path.join(app.root_path, file_name)
            document.write(file_path)
            
            if os.path.isfile(file_path):
                return send_from_directory(
                    directory=app.root_path,
                    filename=file_name,
                    as_attachment=True,
                    cache_timeout=0,
                    mimetype='application/vnd.openxmlformats-officedocument.wordprocessingml.document'
                )
            else:
                return make_response(f"文件 '{file_name}' 不存在.", 404)
        
        # 方式二:内存直接处理(无需写入磁盘)
        # with MailMerge('temp.docx') as document:
        #     document.merge(DN=dn, DD=dd, PA=pa, CU=cr)
        #     f = BytesIO()
        #     document.write(f)
        #     f.seek(0)
        #     return send_file(
        #         f,
        #         mimetype='application/vnd.openxmlformats-officedocument.wordprocessingml.document',
        #         as_attachment=True,
        #         download_name='output.docx'
        #     )
    except Exception as e:
        return make_response(f"错误: {str(e)}", 500)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 03:42:26