如何在Flask中提供静态文件

所以这很尴尬。我在Flask中整合了一个应用程序,目前它只是提供一个静态超文本标记语言页面,其中包含一些指向CSS和JS的链接。我找不到留档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)

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

920961 次浏览

我相信你会在那里找到你需要的:http://flask.pocoo.org/docs/quickstart/#static-files

基本上,您只需要在包的根目录中设置一个“静态”文件夹,然后您可以使用url_for('static', filename='foo.bar')或使用http://example.com/static/foo.bar直接链接到您的文件。

编辑:正如评论中建议的那样,您可以直接使用'/static/foo.bar' URL路径但是url_for()开销(性能方面)非常低,使用它意味着您可以轻松地自定义行为(更改文件夹,更改URL路径,将静态文件移动到S3等)。

我使用的(它一直工作得很好)是一个“模板”目录和一个“静态”目录。我把我所有的. html文件/Flask模板放在模板目录中,静态包含CSS/JS。据我所知,render_template适用于通用的html文件,不管你在多大程度上使用了Flask的模板语法。下面是我views.py文件中的一个示例调用。

@app.route('/projects')
def projects():
return render_template("projects.html", title = 'Projects')

当您确实想要引用单独静态目录中的某个静态文件时,请确保使用url_for()。您可能最终会在html中的CSS/JS文件链接中执行此操作。例如…

<script src="\{\{ url_for('static', filename='styles/dist/js/bootstrap.js') }}"></script>

这里有一个“规范的”非正式Flask教程的链接——这里有很多很棒的技巧来帮助你开始跑步。

http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world

在生产中,在应用程序前面配置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,因为它不能推断文件名或内容类型等内容。

默认情况下,flask使用“模板”文件夹来包含所有模板文件(任何纯文本文件,但通常是.html或某种模板语言,如jinja2)和一个“静态”文件夹来包含所有静态文件(即.js.css和图像)。
在你的routes中,你可以使用render_template()渲染一个模板文件(正如我上面所说,默认情况下它被放置在templates文件夹中)作为你请求的响应。在模板文件(通常是一个类似. html的文件)中,你可能会使用一些.js和/或'. css'文件,所以我猜你的问题是如何将这些静态文件链接到当前模板文件。

基于其他答案的最简单的工作示例如下:

from flask import Flask, request
app = Flask(__name__, static_url_path='')


@app.route('/index/')
def root():
return app.send_static_file('index.html')


if __name__ == '__main__':
app.run(debug=True)

使用名为index.html的超文本标记语言:

<!DOCTYPE html>
<html>
<head>
<title>Hello World!</title>
</head>
<body>
<div>
<p>
This is a test.
</p>
</div>
</body>
</html>

重要事项:index.html在一个名为静态的文件夹中,这意味着<projectpath>.py文件,<projectpath>\statichtml文件。

如果您希望服务器在网络上可见,请使用app.run(debug=True, host='0.0.0.0')

编辑:如果需要显示文件夹中的所有文件,请使用此

@app.route('/<path:path>')
def static_file(path):
return app.send_static_file(path)

这基本上是BlackMamba的答案,所以给他们一个赞成票。

您还可以(这是我最喜欢的)将文件夹设置为静态路径,以便每个人都可以访问其中的文件。

app = Flask(__name__, static_url_path='/static')

使用该设置,您可以使用标准超文本标记语言:

<link rel="stylesheet" type="text/css" href="/static/style.css">

对于创建下一个文件夹树的角度+样板流:

backend/
|
|------ui/
|      |------------------build/          <--'static' folder, constructed by Grunt
|      |--<proj           |----vendors/   <-- angular.js and others here
|      |--     folders>   |----src/       <-- your js
|                         |----index.html <-- your SPA entrypoint
|------<proj
|------     folders>
|
|------view.py  <-- Flask app here

我使用以下解决方案:

...
root = os.path.join(os.path.dirname(os.path.abspath(__file__)), "ui", "build")


@app.route('/<path:path>', methods=['GET'])
def static_proxy(path):
return send_from_directory(root, path)




@app.route('/', methods=['GET'])
def redirect_to_index():
return send_from_directory(root, 'index.html')
...

它有助于将“静态”文件夹重新定义为自定义。

您可以使用此功能:

send_static_file(filename)
内部用于发送静态的函数 文件从静态文件夹到浏览器。

app = Flask(__name__)
@app.route('/<path:path>')
def static_file(path):
return app.send_static_file(path)

所以我得到了工作(基于@user1671599的答案),并想与你们分享。

(我希望我做得对,因为它是我的第一个Python应用程序)

我做了这个-

项目结构:

输入图片描述

server.py:

from server.AppStarter import AppStarter
import os


static_folder_root = os.path.join(os.path.dirname(os.path.abspath(__file__)), "client")


app = AppStarter()
app.register_routes_to_resources(static_folder_root)
app.run(__name__)

AppStarter.py:

from flask import Flask, send_from_directory
from flask_restful import Api, Resource
from server.ApiResources.TodoList import TodoList
from server.ApiResources.Todo import Todo




class AppStarter(Resource):
def __init__(self):
self._static_files_root_folder_path = ''  # Default is current folder
self._app = Flask(__name__)  # , static_folder='client', static_url_path='')
self._api = Api(self._app)


def _register_static_server(self, static_files_root_folder_path):
self._static_files_root_folder_path = static_files_root_folder_path
self._app.add_url_rule('/<path:file_relative_path_to_root>', 'serve_page', self._serve_page, methods=['GET'])
self._app.add_url_rule('/', 'index', self._goto_index, methods=['GET'])


def register_routes_to_resources(self, static_files_root_folder_path):


self._register_static_server(static_files_root_folder_path)
self._api.add_resource(TodoList, '/todos')
self._api.add_resource(Todo, '/todos/<todo_id>')


def _goto_index(self):
return self._serve_page("index.html")


def _serve_page(self, file_relative_path_to_root):
return send_from_directory(self._static_files_root_folder_path, file_relative_path_to_root)


def run(self, module_name):
if module_name == '__main__':
self._app.run(debug=True)

使用redirecturl_for

from flask import redirect, url_for


@app.route('/', methods=['GET'])
def metrics():
return redirect(url_for('static', filename='jenkins_analytics.html'))

这将为您的html中引用的所有文件(css和js…)提供服务器。

如果您只想移动静态文件的位置,那么最简单的方法是在构造函数中声明路径。在下面的示例中,我已将模板和静态文件移动到名为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实例:

嵌套静态烧瓶文件夹

如果您只是试图打开一个文件,您可以使用app.open_resource()。所以读取文件看起来像

with app.open_resource('/static/path/yourfile'):
#code to read the file and do something

想分享……这个例子。

from flask import Flask
app = Flask(__name__)


@app.route('/loading/')
def hello_world():
data = open('sample.html').read()
return data


if __name__ == '__main__':
app.run(host='0.0.0.0')

这工作得更好,更简单。

一个简单的方法去做。干杯!

demo.py

from flask import Flask, render_template
app = Flask(__name__)


@app.route("/")
def index():
return render_template("index.html")


if __name__ == '__main__':
app.run(debug = True)

现在创建名为模板的文件夹名称。 将您的index.html文件添加到模板文件夹

index.html

<!DOCTYPE html>
<html>
<head>
<title>Python Web Application</title>
</head>
<body>
<div>
<p>
Welcomes You!!
</p>
</div>
</body>
</html>

项目结构

-demo.py
-templates/index.html

所有的答案都很好,但对我来说效果很好的只是使用Flask中的简单函数send_file。当host: port/Api Name将在浏览器中显示文件的输出时,只需发送一个html文件作为响应即可


@app.route('/ApiName')
def ApiFunc():
try:
return send_file('some-other-directory-than-root/your-file.extension')
except Exception as e:
logging.info(e.args[0])```


最简单的方法是在主项目文件夹中创建一个静态文件夹。包含. css文件的静态文件夹。

主文件夹

/Main Folder
/Main Folder/templates/foo.html
/Main Folder/static/foo.css
/Main Folder/application.py(flask script)

包含静态和模板文件夹和烧瓶脚本的主文件夹的图像

烧瓶

from flask import Flask, render_template


app = Flask(__name__)


@app.route("/")
def login():
return render_template("login.html")

html(布局)

<!DOCTYPE html>
<html>
<head>
<title>Project(1)</title>
<link rel="stylesheet" href="/static/styles.css">
</head>
<body>
<header>
<div class="container">
<nav>
<a class="title" href="">Kamook</a>
<a class="text" href="">Sign Up</a>
<a class="text" href="">Log In</a>
</nav>
</div>
</header>
{% block body %}
{% endblock %}
</body>
</html>

html

{% extends "layout.html" %}


{% block body %}
<div class="col">
<input type="text" name="username" placeholder="Username" required>
<input type="password" name="password" placeholder="Password" required>
<input type="submit" value="Login">
</div>
{% endblock %}
app = Flask(__name__, static_folder="your path to static")

如果您的根目录中有模板,如果包含该模板的文件也在同一位置,则放置app=Flask(姓名)将起作用,如果该文件在另一个位置,则必须指定模板位置以使Flask指向该位置

可以使用静态端点创建静态文件的URL,如下所示:

url_for('static', filename = 'name_of_file')
<link rel="stylesheet" href="\{\{url_for('static', filename='borders.css')}}" />

默认名为“静态”的文件夹包含所有静态文件 下面是一个代码示例:

<link href="\{\{ url_for('static', filename='vendor/bootstrap/css/bootstrap.min.css') }}" rel="stylesheet">

在静态目录中,在该目录中创建模板目录添加所有html文件为css和javascript创建单独的目录,因为flask将处理或识别模板目录中的所有html文件。

static -
|_ templates
|_ css
|_javascript
|_images

在我的情况下,我需要用户可以访问静态文件夹中的所有文件,以及我需要为我的一些html文件使用模板,以便可以将公共html代码放置在模板中并重用代码。这是我如何一起实现它们的:

from flask import Flask, request, render_template
from flask.json import JSONEncoder


app = Flask(__name__, template_folder='static')




@app.route('/<path:path>')
def serve_static_file(path):
# In my case, only html files are having the template code inside them, like include.
if path.endswith('.html'):
return render_template(path)
# Serve all other files from the static folder directly.
return app.send_static_file(path)

我所有的文件都保存在静态文件夹下,与主烧瓶文件并行。

输入图片描述

这是什么为我工作:

import os
from flask import Flask, render_template, send_from_directory
app = Flask(__name__)




root = os.path.join(os.path.dirname(os.path.abspath(__file__)), "whereyourfilesare")


@app.route('/', methods=['GET'])
def main(request):
path = request.path
if (path == '/'):
return send_from_directory(root, 'index.html')
else:
return send_from_directory(root, path[1:])

我遇到的问题与使用static_url_pathstatic_folder时没有为目录提供index.html文件有关。

以下是我的解决方案:

import os
from flask import Flask, send_from_directory
from flask.helpers import safe_join


app = Flask(__name__)
static = safe_join(os.path.dirname(__file__), 'static')


@app.route('/')
def _home():
return send_from_directory(static, 'index.html')


@app.route('/<path:path>')
def _static(path):
if os.path.isdir(safe_join(static, path)):
path = os.path.join(path, 'index.html')
return send_from_directory(static, path)

例如,要返回我使用的AdSense文件:

@app.route('/ads.txt')
def send_adstxt():
return send_from_directory(app.static_folder, 'ads.txt')