Flask send_file 返回 200 OK 但不发送文件
Posted
技术标签:
【中文标题】Flask send_file 返回 200 OK 但不发送文件【英文标题】:Flask send_file returns 200 OK but does not send file 【发布时间】:2022-01-21 05:26:46 【问题描述】:我有一个相当简单的应用程序,可以使用 Flask send_file 函数下载单个静态文件。无论我是在 Flask run 还是 gunicorn 下运行它,行为都是一样的。路由执行代码,返回 200 OK,但正文中没有数据。下面是代码。我真的很难过。我已阅读有关此主题的所有其他问题,但没有任何效果。 首先是路线:有两条,因为我尝试了两种不同的方法
def download():
print ("download route, basedir and request method", basedir, request.method)
form = DownLoadForm()
id = 1
if form.validate_on_submit():
mac = request.form['macaddr']
mac = mac.lower()
downloadFile(mac)
whitelist = Whitelist.query.all()
# print(whitelist)
return render_template('dnload.html', whitelist=whitelist, form=form)
@app.route('/downloadLog<int:id>', methods=['GET', 'POST'])
def downloadLog(id):
print ("downloadLog request method", request.method)
download = Whitelist.query.get_or_404(id)
mac = download.mac
print("DownloadLog mac: ", mac)
downloadFile(mac)
whitelist = Whitelist.query.all()
return render_template('dnload.html', whitelist = whitelist, form = DownLoadForm())
def downloadFile(mac):
logFileName = "log"+ mac+".csv"
path = os.path.join(app.config['LOG_FOLDER'], mac)
path = os.path.join(basedir, path)
# print ("path in downloadFile: ", path)
if os.path.isfile(path + '/' + logFileName):
filepath = os.path.join(path, logFileName)
print("Downloading Log File: ", filepath)
#this is where the file download occurs
# return send_file(filepath,
# mimetype ='text/csv',
# attachment_filename = logFileName,
# as_attachment=True)
# f = open(filepath, "r")
# for x in range(5):
# a = f.readline()
# print(a)
# f.close()
return send_from_directory(path, logFileName, as_attachment=True, mimetype = 'text/plain')
else:
flash('Error, no mac logs available for download')
其次,downloadLog路由的HTML是
<td>
<a href="url_for('.downloadLog', id=mac.id) ">Download mac.id</a>
</td>
下载路径的 HTML 是 wtf.quick_form。 forms.py 代码是
macaddr = StringField('MAC Address', validators=[DataRequired()])
submit = SubmitField("Download MAC Log File")
这是不包含文件的 OK 内容的wireshark 显示。 0010 04 23 99 bc 40 00 40 06 1b 7c c0 a8 00 23 c0 a8 .#..@.@..|...#..
0020 00 29 13 88 f0 ea 51 28 d6 5b 94 37 8f 3a 50 19 .)....Q(.[.7.:P.
0030 01 f5 37 f8 00 00 74 2e 74 69 6d 65 73 74 61 6d ..7...t.timestam
0040 70 32 3b 0a 20 20 20 20 63 6f 6e 73 74 20 6e 6f p2;. const no
0050 5f 73 75 66 66 69 78 20 3d 20 65 6c 65 6d 2e 64 _suffix = elem.d
0060 61 74 61 73 65 74 2e 6e 6f 73 75 66 66 69 78 3b ataset.nosuffix;
0070 0a 20 20 20 20 63 6f 6e 73 74 20 75 6e 69 74 73 . const units
0080 20 3d 20 65 6c 65 6d 2e 64 61 74 61 73 65 74 2e = elem.dataset.
0090 75 6e 69 74 73 3b 0a 20 20 20 20 6c 65 74 20 61 units;. let a
00a0 72 67 73 20 3d 20 5b 5d 3b 0a 20 20 20 20 69 66 rgs = [];. if
00b0 20 28 66 6f 72 6d 61 74 29 0a 20 20 20 20 20 20 (format).
00c0 20 20 61 72 67 73 2e 70 75 73 68 28 66 6f 72 6d args.push(form
00d0 61 74 29 3b 0a 20 20 20 20 69 66 20 28 74 69 6d at);. if (tim
00e0 65 73 74 61 6d 70 32 29 0a 20 20 20 20 20 20 20 estamp2).
00f0 20 61 72 67 73 2e 70 75 73 68 28 6d 6f 6d 65 6e args.push(momen
0100 74 28 74 69 6d 65 73 74 61 6d 70 32 29 29 3b 0a t(timestamp2));.
0110 20 20 20 20 69 66 20 28 6e 6f 5f 73 75 66 66 69 if (no_suffi
0120 78 29 0a 20 20 20 20 20 20 20 20 61 72 67 73 2e x). args.
0130 70 75 73 68 28 6e 6f 5f 73 75 66 66 69 78 29 3b push(no_suffix);
0140 0a 20 20 20 20 69 66 20 28 75 6e 69 74 73 29 0a . if (units).
0150 20 20 20 20 20 20 20 20 61 72 67 73 2e 70 75 73 args.pus
0160 68 28 75 6e 69 74 73 29 3b 0a 20 20 20 20 65 6c h(units);. el
0170 65 6d 2e 74 65 78 74 43 6f 6e 74 65 6e 74 20 3d em.textContent =
0180 20 74 69 6d 65 73 74 61 6d 70 5b 66 75 6e 63 5d timestamp[func]
0190 2e 61 70 70 6c 79 28 74 69 6d 65 73 74 61 6d 70 .apply(timestamp
01a0 2c 20 61 72 67 73 29 3b 0a 20 20 20 20 65 6c 65 , args);. ele
01b0 6d 2e 63 6c 61 73 73 4c 69 73 74 2e 72 65 6d 6f m.classList.remo
01c0 76 65 28 27 66 6c 61 73 6b 2d 6d 6f 6d 65 6e 74 ve('flask-moment
01d0 27 29 3b 0a 20 20 20 20 65 6c 65 6d 2e 73 74 79 ');. elem.sty
01e0 6c 65 2e 64 69 73 70 6c 61 79 20 3d 20 22 22 3b le.display = "";
01f0 0a 7d 0a 66 75 6e 63 74 69 6f 6e 20 66 6c 61 73 ..function flas
0200 6b 5f 6d 6f 6d 65 6e 74 5f 72 65 6e 64 65 72 5f k_moment_render_
0210 61 6c 6c 28 29 20 7b 0a 20 20 20 20 63 6f 6e 73 all() . cons
0220 74 20 6d 6f 6d 65 6e 74 73 20 3d 20 64 6f 63 75 t moments = docu
0230 6d 65 6e 74 2e 71 75 65 72 79 53 65 6c 65 63 74 ment.querySelect
0240 6f 72 41 6c 6c 28 27 2e 66 6c 61 73 6b 2d 6d 6f orAll('.flask-mo
0250 6d 65 6e 74 27 29 3b 0a 20 20 20 20 6d 6f 6d 65 ment');. mome
0260 6e 74 73 2e 66 6f 72 45 61 63 68 28 66 75 6e 63 nts.forEach(func
0270 74 69 6f 6e 28 6d 6f 6d 65 6e 74 29 20 7b 0a 20 tion(moment) .
0280 20 20 20 20 20 20 20 66 6c 61 73 6b 5f 6d 6f 6d flask_mom
0290 65 6e 74 5f 72 65 6e 64 65 72 28 6d 6f 6d 65 6e ent_render(momen
02a0 74 29 3b 0a 20 20 20 20 20 20 20 20 63 6f 6e 73 t);. cons
02b0 74 20 72 65 66 72 65 73 68 20 3d 20 6d 6f 6d 65 t refresh = mome
02c0 6e 74 2e 64 61 74 61 73 65 74 2e 72 65 66 72 65 nt.dataset.refre
02d0 73 68 3b 0a 20 20 20 20 20 20 20 20 69 66 20 28 sh;. if (
02e0 72 65 66 72 65 73 68 20 26 26 20 72 65 66 72 65 refresh && refre
02f0 73 68 20 3e 20 30 29 20 7b 0a 20 20 20 20 20 20 sh > 0) .
0300 20 20 20 20 20 20 28 66 75 6e 63 74 69 6f 6e 28 (function(
0310 65 6c 65 6d 2c 20 69 6e 74 65 72 76 61 6c 29 20 elem, interval)
0320 7b 0a 20 20 20 20 20 20 20 20 20 20 20 20 20 20 .
0330 20 20 73 65 74 49 6e 74 65 72 76 61 6c 28 66 75 setInterval(fu
0340 6e 63 74 69 6f 6e 28 29 20 7b 0a 20 20 20 20 20 nction() .
0350 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 66 f
0360 6c 61 73 6b 5f 6d 6f 6d 65 6e 74 5f 72 65 6e 64 lask_moment_rend
0370 65 72 28 65 6c 65 6d 29 3b 0a 20 20 20 20 20 20 er(elem);.
0380 20 20 20 20 20 20 20 20 20 20 7d 2c 20 69 6e 74 , int
0390 65 72 76 61 6c 29 3b 0a 20 20 20 20 20 20 20 20 erval);.
03a0 20 20 20 20 7d 29 28 6d 6f 6d 65 6e 74 2c 20 72 )(moment, r
03b0 65 66 72 65 73 68 29 3b 0a 20 20 20 20 20 20 20 efresh);.
03c0 20 7d 0a 20 20 20 20 7d 29 0a 7d 0a 64 6f 63 75 . )..docu
03d0 6d 65 6e 74 2e 61 64 64 45 76 65 6e 74 4c 69 73 ment.addEventLis
03e0 74 65 6e 65 72 28 22 44 4f 4d 43 6f 6e 74 65 6e tener("DOMConten
03f0 74 4c 6f 61 64 65 64 22 2c 20 66 6c 61 73 6b 5f tLoaded", flask_
0400 6d 6f 6d 65 6e 74 5f 72 65 6e 64 65 72 5f 61 6c moment_render_al
0410 6c 29 3b 0a 3c 2f 73 63 72 69 70 74 3e 0a 0a 20 l);.</script>..
0420 20 3c 2f 62 6f 64 79 3e 0a 3c 2f 68 74 6d 6c 3e </body>.</html>
0430 0a .
这是控制台输出:
* Detected change in '/home/mycelium/serveFW/app/routes.py', reloading
* Restarting with stat
* Debugger is active!
* Debugger PIN: 125-099-663
download route, basedir and request method /home/mycelium/serveFW POST
Downloading Log File: /home/mycelium/serveFW/log/fcf5c4abade5/logfcf5c4abade5.csv
192.168.0.41 - - [18/Dec/2021 13:14:43] "POST /download HTTP/1.1" 200 -
download route, basedir and request method /home/mycelium/serveFW POST
Downloading Log File: /home/mycelium/serveFW/log/fcf5c4abade5/logfcf5c4abade5.csv
192.168.0.41 - - [18/Dec/2021 13:14:52] "POST /download HTTP/1.1" 200 -
downloadLog request method GET
DownloadLog mac: fcf5c4abade5
Downloading Log File: /home/mycelium/serveFW/log/fcf5c4abade5/logfcf5c4abade5.csv
192.168.0.41 - - [18/Dec/2021 13:38:05] "GET /downloadLog1 HTTP/1.1" 200 -
【问题讨论】:
您没有从send_from_directory
返回返回值。也就是封装文件下载的响应对象。
我不明白你的评论。我如何不使用 ```return send_from_directory(path, l....) 返回值
仔细检查您的代码。 downloadFile
返回响应,但您将其丢弃在 download()
和 downloadLog()
中。
【参考方案1】:
如果我也使用 make_response,它的行为方式相同。某处基本断开连接,配置等。我修改了响应,如下所示:
def downloadFile(mac):
logFileName = "log"+ mac+".csv"
path = os.path.join(app.config['LOG_FOLDER'], mac)
path = os.path.join(basedir, path)
# print ("path in downloadFile: ", path)
if os.path.isfile(path + '/' + logFileName):
filepath = os.path.join(path, logFileName)
print("Downloading Log File: ", filepath)
#this is where the file download occurs
# return send_file(filepath,
# mimetype ='text/csv',
# attachment_filename = logFileName,
# as_attachment=True)
len = os.path.getsize(filepath)
response = make_response(send_from_directory(path, logFileName, as_attachment=True), 201)
response.headers['Content-Type'] = 'text/html' #this is a test based on what browser says it's accepting.
response.headers['Content-Disposition: attachment; filename'] = logFileName
response.headers['Content-Length'] = len
print("Just before the return, And length", len)
return response
else:
flash('Error, no mac logs available for download')
控制台和wireshark的响应基本上和上面一样。我就是不明白,不管我在别处读过的所有帖子和承诺如何,我尝试的一切似乎都不重要。这是控制台输出:
* Detected change in '/home/mycelium/serveFW/app/routes.py', reloading
* Restarting with stat
* Debugger is active!
* Debugger PIN: 125-099-663
downloadLog request method POST
DownloadLog mac: fcf5c4abade5
Downloading Log File:
/home/mycelium/serveFW/log/fcf5c4abade5/logfcf5c4abade5.csv
Just before the return, And length 183305
192.168.0.41 - - [18/Dec/2021 21:49:00] "POST /downloadLog1 HTTP/1.1" 200 -
【讨论】:
以上是关于Flask send_file 返回 200 OK 但不发送文件的主要内容,如果未能解决你的问题,请参考以下文章