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
相关产品推荐
相关产品推荐

