如何在 Flask 中提供静态文件

新手上路,请多包涵

所以这很尴尬。我有一个应用程序,我把它放在 Flask 中,现在它只是提供一个带有一些 CSS 和 JS 链接的静态 HTML 页面。而且我在文档中找不到 Flask 描述返回静态文件的位置。是的,我可以使用 render_template 但我知道数据没有模板化。我本以为 send_fileurl_for 是正确的,但我无法让它们工作。与此同时,我正在打开文件,阅读内容,并使用适当的 mimetype Response

 import os.path

from flask import Flask, Response

app = Flask(__name__)
app.config.from_object(__name__)

def root_dir():  # pragma: no cover
    return os.path.abspath(os.path.dirname(__file__))

def get_file(filename):  # pragma: no cover
    try:
        src = os.path.join(root_dir(), filename)
        # Figure out how flask returns static files
        # Tried:
        # - render_template
        # - send_file
        # This should not be so non-obvious
        return open(src).read()
    except IOError as exc:
        return str(exc)

@app.route('/', methods=['GET'])
def metrics():  # pragma: no cover
    content = get_file('jenkins_analytics.html')
    return Response(content, mimetype="text/html")

@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def get_resource(path):  # pragma: no cover
    mimetypes = {
        ".css": "text/css",
        ".html": "text/html",
        ".js": "application/javascript",
    }
    complete_path = os.path.join(root_dir(), path)
    ext = os.path.splitext(path)[1]
    mimetype = mimetypes.get(ext, "text/html")
    content = get_file(complete_path)
    return Response(content, mimetype=mimetype)

if __name__ == '__main__':  # pragma: no cover
    app.run(port=80)

有人想为此提供代码示例或网址吗?我知道这将非常简单。

原文由 hughdbrown 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 876
2 个回答

在生产环境中,在您的应用程序前面配置 HTTP 服务器(Nginx、Apache 等)以从静态文件夹向 /static 提供请求。专用的 Web 服务器非常擅长高效地提供静态文件,尽管您可能不会注意到与 Flask 在低容量下的区别。

Flask 会自动创建一个 /static/<path:filename> 路由,该路由将服务于定义 Flask 应用程序的 Python 模块旁边的 static 文件夹下的任何 filename 。使用 url_for 链接到静态文件: url_for('static', filename='js/analytics.js')

您还可以使用 send_from_directory 从您自己的路径中的目录提供文件。这需要一个基本目录和一个路径,并确保路径包含在目录中,这样可以安全地接受用户提供的路径。这在您想在提供文件之前检查某些内容的情况下很有用,例如登录用户是否具有权限。

 from flask import send_from_directory

@app.route('/reports/<path:path>')
def send_report(path):
    return send_from_directory('reports', path)

不要send_filesend_static_file 与用户提供的路径一起使用。这将使您 面临目录遍历攻击send_from_directory 旨在安全地处理已知目录下的用户提供的路径,如果路径试图转义该目录,则会引发错误。

如果您在内存中生成文件而不将其写入文件系统,则可以将 BytesIO 对象传递给 send_file 以像文件一样提供它。在这种情况下,您需要将其他参数传递给 send_file 因为它无法推断文件名或内容类型等内容。

原文由 atupal 发布,翻译遵循 CC BY-SA 4.0 许可协议

如果您只想移动静态文件的位置,那么最简单的方法是在构造函数中声明路径。在下面的示例中,我已将我的模板和静态文件移动到名为 web 的子文件夹中。

 app = Flask(__name__,
            static_url_path='',
            static_folder='web/static',
            template_folder='web/templates')

  • static_url_path='' 从 URL 中删除任何前面的路径(即默认 /static )。
  • static_folder='web/static' 将在文件夹 web/static 中找到的任何文件作为静态文件提供。
  • template_folder='web/templates' 同样,这会更改模板文件夹。

使用此方法,以下 URL 将返回一个 CSS 文件:

 <link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css">

最后,这是文件夹结构的快照,其中 flask_server.py 是 Flask 实例:

嵌套静态 Flask 文件夹

原文由 Richard Dunn 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题