如何在烧瓶中服务静态文件

时间:2022-04-27 16:54:55

So this is embarrassing. I've got an application that I threw together in Flask and for now it is just serving up a single static HTML page with some links to CSS and JS. And I can't find where in the documentation Flask describes returning static files. Yes, I could use render_template but I know the data is not templatized. I'd have thought send_file or url_for was the right thing, but I could not get those to work. In the meantime, I am opening the files, reading content, and rigging up a Response with appropriate mimetype:

这是令人尴尬的。我在Flask中添加了一个应用程序,现在它只提供一个静态HTML页面,其中包含一些CSS和JS的链接。我也找不到Flask文件中描述返回静态文件的地方。是的,我可以使用render_template但是我知道数据不是模板化的。我认为send_file或url_for是正确的,但是我不能让它们工作。与此同时,我打开文件,阅读内容,用适当的mimetype建立一个响应:

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)

Someone want to give a code sample or url for this? I know this is going to be dead simple.

有人想给它一个代码示例或url吗?我知道这很简单。

12 个解决方案

#1


394  

The preferred method is to use nginx or another web server to serve static files; they'll be able to do it more efficiently than Flask.

首选的方法是使用nginx或其他web服务器来服务静态文件;他们能比烧瓶做得更有效率。

However, you can use send_from_directory to send files from a directory, which can be pretty convenient in some situations:

但是,您可以使用send_from_directory从目录发送文件,在某些情况下这非常方便:

from flask import Flask, request, send_from_directory

# set the project root directory as the static folder, you can set others.
app = Flask(__name__, static_url_path='')

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

if __name__ == "__main__":
    app.run()

Do not use send_file or send_static_file with an user-supplied path.

不要对用户提供的路径使用send_file或send_static_file。

send_static_file example:

send_static_file例子:

from flask import Flask, request
# set the project root directory as the static folder, you can set others.
app = Flask(__name__, static_url_path='')

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

#2


59  

I'm sure you'll find what you need there: http://flask.pocoo.org/docs/quickstart/#static-files

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

Basically you just need a "static" folder at the root of your package, and then you can use url_for('static', filename='foo.bar') or directly link to your files with http://example.com/static/foo.bar.

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

EDIT: As suggested in the comments you could directly use the '/static/foo.bar' URL path BUT url_for() overhead (performance wise) is quite low, and using it means that you'll be able to easily customise the behaviour afterwards (change the folder, change the URL path, move your static files to S3, etc).

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

#3


53  

You can also, and this is my favorite, set a folder as static path so that the files inside are reachable for everyone.

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

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

With that set you can use the standard HTML:

有了这个设置,您可以使用标准的HTML:

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

#4


29  

What I use (and it's been working great) is a "templates" directory and a "static" directory. I place all my .html files/Flask templates inside the templates directory, and static contains CSS/JS. render_template works fine for generic html files to my knowledge, regardless of the extent at which you used Flask's templating syntax. Below is a sample call in my views.py file.

我使用的是一个“模板”目录和一个“静态”目录。我将所有的.html文件/Flask模板放在模板目录中,而static包含CSS/JS。据我所知,render_template适用于一般的html文件,无论您在多大程度上使用Flask的模板语法。下面是我的观点中的一个示例调用。py文件。

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

Just make sure you use url_for() when you do want to reference some static file in the separate static directory. You'll probably end up doing this anyways in your CSS/JS file links in html. For instance...

当您确实希望在单独的静态目录中引用某个静态文件时,请确保使用url_for()。无论如何,在html的CSS/JS文件链接中,您可能最终会这样做。例如……

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

Here's a link to the "canonical" informal Flask tutorial - lots of great tips in here to help you hit the ground running.

这里有一个“权威的”非正式Flask教程的链接-这里有很多很棒的技巧来帮助你开始工作。

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

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

#5


28  

A simplest working example based on the other answers is the following:

基于其他答案的一个最简单的工作示例是:

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)

With the HTML called index.html:

使用名为index.html的HTML:

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

IMPORTANT: And index.html is in a folder called static, meaning <projectpath> has the .py file, and <projectpath>\static has the html file.

重要:和索引。html在一个名为static的文件夹中,这意味着 有.py文件, \static有html文件。

If you want the server to be visible on the network, use app.run(debug=True, host='0.0.0.0')

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

EDIT: For showing all files in the folder if requested, use this

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

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

Which is essentially BlackMamba's answer, so give them an upvote.

这基本上就是黑曼巴的答案,所以给他们一个向上的投票。

#6


28  

You can use this function :

你可以使用这个功能:

send_static_file(filename)
Function used internally to send static files from the static folder to the browser.

send_static_file(文件名)函数,用于在内部将静态文件夹中的静态文件发送到浏览器。

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

#7


17  

If you just want to move the location of your static files, then the simplest method is to declare the paths in the constructor. In the example below, I have moved my templates and static files into a sub-folder called web.

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

app = Flask(__name__,
            static_url_path='', 
            static_folder='web/static',
            template_folder='web/templates')
  • static_url_path='' removes any preceding path from the URL (i.e. the default /static).
  • static_url_path=“从URL(即默认/静态)删除任何前面的路径”。
  • static_folder='web/static' will tell Flask serve the files found at web/static.
  • static_folder='web/static'将告诉Flask服务在web/static中找到的文件。
  • template_folder='web/templates', similarly, this changes the templates folder.
  • template_folder='web/模板',类似地,这会更改templates文件夹。

Using this method, the following URL will return a CSS file:

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

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

And finally, here's a snap of the folder structure, where flask_server.py is the Flask instance:

最后,这里是文件夹结构的快照,flask_server。py是Flask实例:

如何在烧瓶中服务静态文件

#8


5  

For angular+boilerplate flow which creates next folders tree:

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

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

I use following solution:

我用以下解决方案:

...
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')
...

It helps to redefine 'static' folder to custom.

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

#9


5  

So I got things working (based on @user1671599 answer) and wanted to share it with you guys.

所以我让东西工作(基于@user1671599的答案)并且想和你们分享它。

(I hope I'm doing it right since it's my first app in Python)

(我希望我做得对,因为这是我在Python里的第一个应用)

I did this -

我这样做,

Project structure:

项目结构:

如何在烧瓶中服务静态文件

server.py:

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:

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)

#10


2  

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

This servers all the files (css & js...) referenced in your html file.

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

#11


1  

   By default, flask use a "templates" folder to contain all your template files(any plain-text file, but usually .html or some kind of template language such as jinja2 ) & a "static" folder to contain all your static files(i.e. .js .css and your images).
   In your routes, u can use render_template() to render a template file (as I say above, by default it is placed in the templates folder) as the response for your request. And in the template file (it's usually a .html-like file), u may use some .js and/or `.css' files, so I guess your question is how u link these static files to the current template file.

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

#12


0  

If you are just trying to open a file, you could use app.open_resource(). So reading a file would look something like

如果您只是尝试打开一个文件,您可以使用app.open_resource()。所以读取文件应该是这样的

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

#1


394  

The preferred method is to use nginx or another web server to serve static files; they'll be able to do it more efficiently than Flask.

首选的方法是使用nginx或其他web服务器来服务静态文件;他们能比烧瓶做得更有效率。

However, you can use send_from_directory to send files from a directory, which can be pretty convenient in some situations:

但是,您可以使用send_from_directory从目录发送文件,在某些情况下这非常方便:

from flask import Flask, request, send_from_directory

# set the project root directory as the static folder, you can set others.
app = Flask(__name__, static_url_path='')

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

if __name__ == "__main__":
    app.run()

Do not use send_file or send_static_file with an user-supplied path.

不要对用户提供的路径使用send_file或send_static_file。

send_static_file example:

send_static_file例子:

from flask import Flask, request
# set the project root directory as the static folder, you can set others.
app = Flask(__name__, static_url_path='')

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

#2


59  

I'm sure you'll find what you need there: http://flask.pocoo.org/docs/quickstart/#static-files

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

Basically you just need a "static" folder at the root of your package, and then you can use url_for('static', filename='foo.bar') or directly link to your files with http://example.com/static/foo.bar.

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

EDIT: As suggested in the comments you could directly use the '/static/foo.bar' URL path BUT url_for() overhead (performance wise) is quite low, and using it means that you'll be able to easily customise the behaviour afterwards (change the folder, change the URL path, move your static files to S3, etc).

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

#3


53  

You can also, and this is my favorite, set a folder as static path so that the files inside are reachable for everyone.

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

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

With that set you can use the standard HTML:

有了这个设置,您可以使用标准的HTML:

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

#4


29  

What I use (and it's been working great) is a "templates" directory and a "static" directory. I place all my .html files/Flask templates inside the templates directory, and static contains CSS/JS. render_template works fine for generic html files to my knowledge, regardless of the extent at which you used Flask's templating syntax. Below is a sample call in my views.py file.

我使用的是一个“模板”目录和一个“静态”目录。我将所有的.html文件/Flask模板放在模板目录中,而static包含CSS/JS。据我所知,render_template适用于一般的html文件,无论您在多大程度上使用Flask的模板语法。下面是我的观点中的一个示例调用。py文件。

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

Just make sure you use url_for() when you do want to reference some static file in the separate static directory. You'll probably end up doing this anyways in your CSS/JS file links in html. For instance...

当您确实希望在单独的静态目录中引用某个静态文件时,请确保使用url_for()。无论如何,在html的CSS/JS文件链接中,您可能最终会这样做。例如……

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

Here's a link to the "canonical" informal Flask tutorial - lots of great tips in here to help you hit the ground running.

这里有一个“权威的”非正式Flask教程的链接-这里有很多很棒的技巧来帮助你开始工作。

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

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

#5


28  

A simplest working example based on the other answers is the following:

基于其他答案的一个最简单的工作示例是:

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)

With the HTML called index.html:

使用名为index.html的HTML:

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

IMPORTANT: And index.html is in a folder called static, meaning <projectpath> has the .py file, and <projectpath>\static has the html file.

重要:和索引。html在一个名为static的文件夹中,这意味着 有.py文件, \static有html文件。

If you want the server to be visible on the network, use app.run(debug=True, host='0.0.0.0')

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

EDIT: For showing all files in the folder if requested, use this

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

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

Which is essentially BlackMamba's answer, so give them an upvote.

这基本上就是黑曼巴的答案,所以给他们一个向上的投票。

#6


28  

You can use this function :

你可以使用这个功能:

send_static_file(filename)
Function used internally to send static files from the static folder to the browser.

send_static_file(文件名)函数,用于在内部将静态文件夹中的静态文件发送到浏览器。

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

#7


17  

If you just want to move the location of your static files, then the simplest method is to declare the paths in the constructor. In the example below, I have moved my templates and static files into a sub-folder called web.

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

app = Flask(__name__,
            static_url_path='', 
            static_folder='web/static',
            template_folder='web/templates')
  • static_url_path='' removes any preceding path from the URL (i.e. the default /static).
  • static_url_path=“从URL(即默认/静态)删除任何前面的路径”。
  • static_folder='web/static' will tell Flask serve the files found at web/static.
  • static_folder='web/static'将告诉Flask服务在web/static中找到的文件。
  • template_folder='web/templates', similarly, this changes the templates folder.
  • template_folder='web/模板',类似地,这会更改templates文件夹。

Using this method, the following URL will return a CSS file:

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

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

And finally, here's a snap of the folder structure, where flask_server.py is the Flask instance:

最后,这里是文件夹结构的快照,flask_server。py是Flask实例:

如何在烧瓶中服务静态文件

#8


5  

For angular+boilerplate flow which creates next folders tree:

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

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

I use following solution:

我用以下解决方案:

...
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')
...

It helps to redefine 'static' folder to custom.

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

#9


5  

So I got things working (based on @user1671599 answer) and wanted to share it with you guys.

所以我让东西工作(基于@user1671599的答案)并且想和你们分享它。

(I hope I'm doing it right since it's my first app in Python)

(我希望我做得对,因为这是我在Python里的第一个应用)

I did this -

我这样做,

Project structure:

项目结构:

如何在烧瓶中服务静态文件

server.py:

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:

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)

#10


2  

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

This servers all the files (css & js...) referenced in your html file.

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

#11


1  

   By default, flask use a "templates" folder to contain all your template files(any plain-text file, but usually .html or some kind of template language such as jinja2 ) & a "static" folder to contain all your static files(i.e. .js .css and your images).
   In your routes, u can use render_template() to render a template file (as I say above, by default it is placed in the templates folder) as the response for your request. And in the template file (it's usually a .html-like file), u may use some .js and/or `.css' files, so I guess your question is how u link these static files to the current template file.

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

#12


0  

If you are just trying to open a file, you could use app.open_resource(). So reading a file would look something like

如果您只是尝试打开一个文件,您可以使用app.open_resource()。所以读取文件应该是这样的

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