Flasche ist Pythons leichtes Webanwendungsframework. Web-Apps generieren manchmal Dateien auf der Serverseite und laden sie herunter. Dieses Mal werde ich über die Implementierung des Dateidownloads in Bottle schreiben.
Ich denke, dass Sie in Webanwendungen häufig ein Verzeichnis erstellen, in dem Bilder / CSS / JS-Dateien wie "/ static /" erfasst werden. In solchen Fällen können Sie jedoch keine Anforderungshandler einzeln mit der Funktion "route" erstellen Es ist zweckmäßig, die Funktion "static_file" von "Flasche" wie folgt zu verwenden.
In diesem Beispiel liefert der Zugriff auf "http: // localhost: 8080 / static / hoge.txt" den Inhalt von "hoge.txt" in ". / Static", wie aus dem aktuellen Verzeichnis zur Laufzeit ersichtlich.
Bei der Produktionsbereitstellung vieler Webanwendungen wird das Verzeichnis, in dem statische Dateien erfasst werden, normalerweise direkt von Nginx oder Apache bereitgestellt. Wenn Sie jedoch in Flaschen geschriebene Python-Apps unterstützen, können Sie statische Dateien während der lokalen Entwicklung lesen. (Im Vergleich zu unserer Firma)
# -*- coding: utf-8 -*-
from bottle import route, run, static_file
@route('/static/<file_path:path>')
def static(file_path):
return static_file(file_path, root='./static')
run(host='localhost', port=8080)
Wenn man sich [Flaschenquelle] ansieht (https://github.com/bottlepy/bottle/blob/master/bottle.py#L2651), scheint es, dass die wichtigsten Dateiformate durch das Paket "mimetypes" durch Erweiterung abgeleitet werden. ist. Gängige Dateien wie Bilder, CSS- und Zip / GZ-Dateien haben wahrscheinlich den richtigen Mimetyp im HTTP-Header "Content-Type".
Setzen wir die Option "Download" der Funktion "static_file" auf "True".
# -*- coding: utf-8 -*-
from bottle import route, run, static_file
@route('/static/<file_path:path>')
def static(file_path):
return static_file(file_path, root='./static', download=True)
run(host='localhost', port=8080)
Wenn Sie den zu lesenden Dateinamen und den vom Browser zu speichernden Dateinamen trennen möchten, legen Sie den im Browser zu speichernden Dateinamen in der Option "Download" fest. Details werden später im Abschnitt "Static_file-Funktionsargumente / -optionen" beschrieben.
Sie können die Funktion static_file
so wie sie ist verwenden.
# -*- coding: utf-8 -*-
from bottle import route, run, static_file
@route('/sample_image.png')
def sample_image():
return static_file('./my_sample_image.png', root='.')
run(host='localhost', port=8080)
Bei Implementierung mit "HTTPResponse" wäre dies wie folgt.
Dies scheint nützlich zu sein, wenn Sie den Inhalt der Datei zur Laufzeit bearbeiten und schwierige Dinge wie die Verteilung ausführen müssen.
Wenn Sie jedoch nur eine vorhandene Datei herunterladen möchten, ist es grundsätzlich einfach und zuverlässig, die Funktion static_file
zu verwenden.
Mit der Funktion static_file
können Sie sich um Details wie das Schätzen des Mimetyps und das Erstellen einer 404-Antwort kümmern, wenn die Datei nicht vorhanden ist.
# -*- coding: utf-8 -*-
from bottle import route, run, template, response
@route('/sample_image.png')
def sample_image():
response.content_type = 'image/png'
with open('./my_sample_image.png', 'rb') as fh:
content = fh.read()
response.set_header('Content-Length', str(len(content)))
return content
run(host='localhost', port=8080)
Wenn Sie nun auf "http: // localhost: 8080 / sample_image.png " zugreifen, wird das Bild angezeigt.
Der Handler für die von Bottle aufgerufene HTTP-Anforderung verwendet die Eigenschaft, dass der Rückgabewert des Handlers so wie er ist zum Hauptteil der Antwort wird. Der HTTP-Antwortheader wird geändert, indem das Antwortobjekt des Flaschenpakets unverändert geändert wird. Persönlich ziehe ich es vor, ein HTTPResponse-Objekt wie das folgende explizit zusammenzustellen und zurückzugeben.
# -*- coding: utf-8 -*-
from bottle import route, run, template, HTTPResponse
@route('/sample_image.png')
def sample_image():
with open('./my_sample_image.png', 'rb') as fh:
content = fh.read()
resp = HTTPResponse(status=200, body=content)
resp.content_type = 'image/png'
resp.set_header('Content-Length', str(len(content)))
return resp
run(host='localhost', port=8080)
Wenn der Rückgabewert des Handlers HTTPResponse ist, gibt der Handler für die von Bottle aufgerufene HTTP-Anforderung die Antwort gemäß dem Inhalt des HTTPResponse-Objekts zurück. Weitere Informationen zu HTTPResponse finden Sie unter Request / Response-Objekt von Mastering Bottle.
Große Dateien, die nicht in den Speicher passen, müssen nach und nach aus der Datei gelesen und in den Socket geschrieben werden.
Auch in solchen Fällen kann static_file
verwendet werden. static_file
ist keine Antwort, bei der der gesamte Inhalt der Datei gelesen wird, sondern eine Implementierung, die die Datei nach und nach intern liest und verteilt.
Nach der Untersuchung scheint es, dass, wenn der Flaschenhandler ein Generator wird, jedes vom Generator erzeugte Element als zerlegtes Fragment des Körpers an den Client gesendet wird. Selbst in der [Quelle] von static_file
(https://github.com/bottlepy/bottle/blob/master/bottle.py#L2725) wird der Inhalt nach und nach von der Generatorfunktion _file_iter_range
gelesen und zur Antwort. Und es scheint.
Wenn Sie es selbst implementieren, wird es wie folgt sein.
# -*- coding: utf-8 -*-
from bottle import route, run, template, response
@route('/sample_image.png')
def sample_image():
response.content_type = 'image/png'
bufsize = 1024 # 1KB
with open('./my_sample_image.png', 'rb') as fh:
while True:
buf = fh.read(bufsize)
if len(buf) == 0:
break # EOF
yield buf
run(host='localhost', port=8080)
Sie müssen sich nicht an diese Methode erinnern, da es eine static_file
gibt? Es gibt auch eine Geschichte,
Ich denke, es kann eine Implementierung geben, z. B. das sofortige Lesen aus der Datenbank, ohne eine Datei durchzugehen, sie in ein CSV-Dateiformat zu verarbeiten und an den Client zu senden. Tatsächlich habe ich herausgefunden, wie es in einem solchen Fall geht, also hoffe ich, dass es jemand anderem hilft.
Wenn Sie das Objekt "HTTPResponse" in Form von "return" implementieren möchten, setzen Sie den Generator auf "body" des Objekts "HTTPResponse".
# -*- coding: utf-8 -*-
from bottle import route, run, template, HTTPResponse
@route('/sample_image.png')
def sample_image():
resp = HTTPResponse(status=200)
resp.content_type = 'image/png'
def _file_content_iterator():
bufsize = 1024 # 1KB
with open('./my_sample_image.png', 'rb') as fh:
while True:
buf = fh.read(bufsize)
if len(buf) == 0:
break # EOF
yield buf
resp.body = _file_content_iterator()
return resp
run(host='localhost', port=8080)
Diese Methode kann jedoch auch etwas unangenehm sein, da sie auf den ersten Blick schwer zu verstehen ist, z. B. das Definieren einer Funktion innerhalb einer Funktion. Das ist dein Favorit.
Die Implementierung des Generators mag für diejenigen, die Python noch nicht kennen, schwer zu verstehen sein, aber ich habe einen Artikel über Python-Iteratoren / Generatoren [Python-Iteratoren und -Generatoren] geschrieben (http://qiita.com/tomotaka_ito/items/35f3eb108f587022fa09). Bitte schauen Sie, wenn Sie möchten.
Es geht mehr um HTTP als um Flasche, aber Sie können dies mit dem Header "Content-Disposition" tun. Wenn Sie die Funktion "static_file" verwenden möchten, können Sie die Option "download" wie oben beschrieben auf "True" setzen. Hier werde ich die Implementierung der Interaktion mit "HTTPResponse" vorstellen.
# -*- coding: utf-8 -*-
from bottle import route, run, template, response
@route('/sample_image.png')
def sample_image():
response.content_type = 'image/png'
with open('./my_sample_image.png', 'rb') as fh:
content = fh.read()
response.set_header('Content-Length', str(len(content)))
download_fname = 'hoge.png'
response.set_header('Content-Disposition', 'attachment; filename="%s"' % download_fname.encode('utf-8'))
return content
run(host='localhost', port=8080)
Wenn Sie nun auf "http: // localhost: 8080 / sample_image.png " zugreifen, wird das Bild unter dem Dateinamen "hoge.png " gespeichert.
Die Signatur der Funktion static_file
lautet wie folgt.
def static_file(filename, root,
mimetype='auto',
download=False,
charset='UTF-8'):
....
--Dateiname
: Der Name der Datei in root
, die den Inhalt enthält, den Sie liefern möchten.
--root
: Das Verzeichnis mit der Datei filename
, die den Inhalt enthält, den Sie liefern möchten.
mimetype
: Optional. Standardmäßig wird es automatisch vom Paket mimetypes
erraten.
--download
: Optional. Wenn Sie in Form eines Speicherdialogs oder automatisch im Download-Ordner herunterladen möchten, geben Sie beim Speichern auf der Clientseite "True" oder den Namen als Zeichenfolge an. False
für Inline-Anzeige. Der Standardwert ist "False"Recommended Posts