How to serve static files in Flask
P粉754473468
2023-08-23 15:50:41
<p>So this is embarrassing. I've put together an app in <code>Flask</code> and currently it just serves a static HTML page with some links to CSS and JS. I can't find a place in the documentation for <code>Flask</code> that describes returning static files. Yes, I can use <code>render_template</code> but I know the data is not templated. I think <code>send_file</code> or <code>url_for</code> are correct, but I can't get them to work. In the meantime, I open the file, read the contents, and set the <code>Response</code> using the appropriate mimetype: </p>
<pre class="brush:php;toolbar:false;">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)</pre>
<p>Does anyone want to provide a code sample or URL for this? I knew it would be very simple. </p>
If you just want to move the location of the static files, the easiest way is to declare the path in the constructor. In the example below, I've moved the templates and static files into a subfolder called
web
.static_url_path=''
Remove all preceding paths from the URL.static_folder='web/static'
Serves any files found in the folderweb/static
As a static file.template_folder='web/templates'
Similarly, this changes Template folder.Using this method, the following URL will return the CSS file:
Finally, here is a snapshot of the folder structure, where
flask_server.py
is the Flask instance:In production, configure an HTTP server (Nginx, Apache, etc.) in front of the application to handle
/static
requests from the static folder. Dedicated web servers are very good at serving static files efficiently, although at low volumes you may not notice the difference compared to Flask.Flask will automatically create a
/static/
route that will serve anyfilename
under thestatic
folder next to Python Modules that define Flask applications. Useurl_for
to link to static files:url_for('static', filename='js/analytics.js')
You can also use
send_from_directory
to serve files from a directory in your own route. This takes a base directory and a path, and ensures that the path is contained within that directory so that user-supplied paths can be safely accepted. This can be useful if you want to check something before serving the file, such as whether the logged in user has permissions.Do not use
send_file
orsend_static_file
with a user-supplied path. This will expose you to a directory traversal attack.send_from_directory
Designed to safely handle user-supplied paths to known directories, raising an error if the path attempts to escape the directory.If you are generating the file in memory without writing it to the file system, you can provide it as a file by passing a
BytesIO
object tosend_file
. In this case you need to pass additional parameters tosend_file
as it cannot infer things like filename or content type.