使用 mod_wsgi 在 apache 上提供 Flask 应用程序时考虑文件路径的正确方法是什么
What's the proper way to think about filepaths with a Flask application being served on apache with mod_wsgi
我正在尝试允许用户从我的 Flask 应用程序下载 csv 文件,但在处理从 ubuntu 18 服务器 运行 Apache2 下载文件的路径中。
import flask
import os
from io import BytesIO
basedir = os.path.abspath(os.path.dirname(__file__))
app = flask.Flask(__name__)
app.config["DEBUG"] = True
@app.route('/<string:report>/<string:action>', methods=['GET'])
def report(report,action):
if action == 'download':
files = os.listdir(os.path.join(basedir, f'static/reports/{report}'))
filepath = url_for(f'static/reports/{report}/{files[-1]}')
output = BytesIO()
with open(filepath, 'rb') as f:
data = f.read()
output.write(data)
output.seek(0)
return send_file(output,attachment_filename=files[-1], as_attachment=True)
但我收到此错误:[Errno 2] No such file or directory: '/static/reports'
我的 Apache2 配置已经有静态文件的别名
像这样:
Alias /static /var/www/FlaskApp/FlaskApp/static
<Directory /var/www/FlaskApp/FlaskApp/static/>
Order allow,deny
Allow from all
</Directory>
我也试过在 static 下为我的 reports 文件夹创建一个别名,但我仍然得到相同的结果。
有什么明显的我遗漏的东西吗?
您的错误是使用 url_for()
生成路径。 url_for()
生成 URL 路径,而不是文件系统路径。您不能使用结果打开本地文件。 url_for()
用于将 浏览器 发送到正确的位置。
您正在从标准 static
路径提供文件。只需弄清楚 Flask 的位置,app
/ current_app
对象 has a .static_folder
attribute.
您还想使用 send_from_directory()
function 直接提供文件。这里不需要先将数据加载到 BytesIO()
对象中。 send_from_directory
接受相对路径作为第二个参数。
这应该有效:
@app.route('/<string:report>/<string:action>', methods=['GET'])
def report(report, action):
if action == 'download':
files = os.listdir(os.path.join(app.static_folder, 'reports', report))
filename = files[-1]
filepath = os.path.join('reports', report, filename)
return send_from_directory(app.static_folder, filepath, as_attachment=True)
我省略了attachment_filename
,因为默认已经使用正在提供的文件的文件名。
您可能需要重新考虑 files[-1]
策略。 os.listdir()
以任意顺序生成文件(OS 决定的顺序最方便)。如果您希望它是最近创建或修改的文件,则必须先进行自己的排序。
我正在尝试允许用户从我的 Flask 应用程序下载 csv 文件,但在处理从 ubuntu 18 服务器 运行 Apache2 下载文件的路径中。
import flask
import os
from io import BytesIO
basedir = os.path.abspath(os.path.dirname(__file__))
app = flask.Flask(__name__)
app.config["DEBUG"] = True
@app.route('/<string:report>/<string:action>', methods=['GET'])
def report(report,action):
if action == 'download':
files = os.listdir(os.path.join(basedir, f'static/reports/{report}'))
filepath = url_for(f'static/reports/{report}/{files[-1]}')
output = BytesIO()
with open(filepath, 'rb') as f:
data = f.read()
output.write(data)
output.seek(0)
return send_file(output,attachment_filename=files[-1], as_attachment=True)
但我收到此错误:[Errno 2] No such file or directory: '/static/reports'
我的 Apache2 配置已经有静态文件的别名 像这样:
Alias /static /var/www/FlaskApp/FlaskApp/static
<Directory /var/www/FlaskApp/FlaskApp/static/>
Order allow,deny
Allow from all
</Directory>
我也试过在 static 下为我的 reports 文件夹创建一个别名,但我仍然得到相同的结果。
有什么明显的我遗漏的东西吗?
您的错误是使用 url_for()
生成路径。 url_for()
生成 URL 路径,而不是文件系统路径。您不能使用结果打开本地文件。 url_for()
用于将 浏览器 发送到正确的位置。
您正在从标准 static
路径提供文件。只需弄清楚 Flask 的位置,app
/ current_app
对象 has a .static_folder
attribute.
您还想使用 send_from_directory()
function 直接提供文件。这里不需要先将数据加载到 BytesIO()
对象中。 send_from_directory
接受相对路径作为第二个参数。
这应该有效:
@app.route('/<string:report>/<string:action>', methods=['GET'])
def report(report, action):
if action == 'download':
files = os.listdir(os.path.join(app.static_folder, 'reports', report))
filename = files[-1]
filepath = os.path.join('reports', report, filename)
return send_from_directory(app.static_folder, filepath, as_attachment=True)
我省略了attachment_filename
,因为默认已经使用正在提供的文件的文件名。
您可能需要重新考虑 files[-1]
策略。 os.listdir()
以任意顺序生成文件(OS 决定的顺序最方便)。如果您希望它是最近创建或修改的文件,则必须先进行自己的排序。