807 Stimmen

Wie man statische Dateien in Flask bereitstellt

Also das ist peinlich. Ich habe eine Anwendung in Flask zusammengeworfen und derzeit dient sie nur dazu, eine einzelne statische HTML-Seite mit einigen Links zu CSS und JS bereitzustellen. Und ich kann nicht finden, wo in der Dokumentation Flask beschreibt, wie man statische Dateien zurückgibt. Ja, ich könnte render_template verwenden, aber ich weiß, dass die Daten nicht in Templates aufbereitet sind. Ich hätte gedacht, dass send_file oder url_for das Richtige wären, aber ich konnte diese nicht zum Laufen bringen. In der Zwischenzeit öffne ich die Dateien, lese den Inhalt und richte eine Response mit dem entsprechenden Mimetyp ein:

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)
        # Herausfinden, wie flask statische Dateien zurückgibt
        # Versucht:
        # - render_template
        # - send_file
        # Das sollte nicht so unklar sein
        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('/')
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)

Kann mir jemand ein Code-Beispiel oder eine URL dafür geben? Ich weiß, dass das total einfach sein wird.

932voto

atupal Punkte 15076

Bei der Produktion konfigurieren Sie den HTTP-Server (Nginx, Apache usw.) vor Ihrer Anwendung, um Anfragen an /static aus dem statischen Ordner zu bedienen. Ein dedizierter Webserver ist sehr gut darin, statische Dateien effizient zu bedienen, obwohl Sie bei niedrigen Volumina wahrscheinlich keinen Unterschied im Vergleich zu Flask feststellen werden.

Flask erstellt automatisch einen /static/ Route, der jede filename unter dem static Ordner neben dem Python-Modul, das Ihre Flask-Anwendung definiert, bedienen wird. Verwenden Sie url_for, um auf statische Dateien zu verlinken: url_for('static', filename='js/analytics.js')

Sie können auch send_from_directory verwenden, um Dateien aus einem Verzeichnis in Ihrer eigenen Route zu bedienen. Dies nimmt ein Basisverzeichnis und einen Pfad und stellt sicher, dass der Pfad im Verzeichnis enthalten ist, was es sicher macht, benutzerbereitgestellte Pfade zu akzeptieren. Dies kann nützlich sein, wenn Sie etwas überprüfen möchten, bevor Sie die Datei bereitstellen, z.B. ob der angemeldete Benutzer Berechtigung hat.

from flask import send_from_directory

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

Verwenden Sie nicht send_file oder send_static_file mit einem benutzerbereitgestellten Pfad. Dies setzt Sie einem Verzeichnis-Traversierungsangriff aus. send_from_directory wurde entwickelt, um benutzerbereitgestellte Pfade sicher unter einem bekannten Verzeichnis zu behandeln, und wird einen Fehler auslösen, wenn der Pfad versucht, aus dem Verzeichnis auszubrechen.

Wenn Sie eine Datei im Speicher erzeugen, ohne sie auf das Dateisystem zu schreiben, können Sie ein BytesIO-Objekt an send_file übergeben, um es wie eine Datei zu bedienen. In diesem Fall müssen Sie andere Argumente an send_file übergeben, da es Dinge wie den Dateinamen oder den Inhaltstyp nicht ableiten kann.

308voto

Richard Dunn Punkte 5750

Wenn Sie nur den Speicherort Ihrer statischen Dateien verschieben möchten, ist die einfachste Methode, die Pfade im Konstruktor zu deklarieren. Im folgenden Beispiel habe ich meine Vorlagen- und statischen Dateien in einen Unterordner namens web verschoben.

app = Flask(__name__,
            static_url_path='', 
            static_folder='web/static',
            template_folder='web/templates')
  • static_url_path='' entfernt jeden vorangestellten Pfad aus der URL.
  • static_folder='web/static', um Dateien im Ordner web/static als statische Dateien zu verwenden.
  • template_folder='web/templates' ändert entsprechend den Vorlagenorder.

Mit dieser Methode gibt die folgende URL eine CSS-Datei zurück:

Und schließlich hier eine Ansicht der Ordnerstruktur, in der flask_server.py die Flask-Instanz ist:

Nested Static Flask Folders

123voto

sharpshadow Punkte 1168

Sie können auch - und das ist mein Favorit - einen Ordner als statischen Pfad festlegen, so dass die Dateien darin für alle erreichbar sind.

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

Mit dieser Einstellung können Sie das Standard-HTML verwenden:

92voto

b4stien Punkte 1780

Ich bin sicher, dass du dort finden wirst, was du brauchst: http://flask.pocoo.org/docs/quickstart/#static-files

Im Grunde benötigst du nur einen "static" Ordner im Root deines Pakets, und dann kannst du url_for('static', filename='foo.bar') verwenden oder direkt auf deine Dateien verlinken mit http://example.com/static/foo.bar.

Wie in den Kommentaren vorgeschlagen, könntest du direkt den '/static/foo.bar' URL-Pfad verwenden ABER der Overhead von url_for() (was die Leistung betrifft) ist recht gering, und wenn du es verwendest, bedeutet das, dass du das Verhalten anschließend leicht anpassen kannst (den Ordner ändern, den URL-Pfad ändern, deine statischen Dateien nach S3 verschieben, etc).

56voto

BlackMamba Punkte 9582

Sie können diese Funktion verwenden:

send_static_file(filename)
Funktion, die intern verwendet wird, um statische Dateien aus dem statischen Ordner an den Browser zu senden.

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X