Laden Sie Dateien in Google App Engine hoch


79

Ich plane, eine Web-App zu erstellen, mit der Benutzer ihre Visual Studio-Projektdateien herunterstufen können. Es scheint jedoch, dass Google App Engine das Hochladen von Dateien und das Speichern von Flatfiles auf dem Google Server über db.TextPropertyund akzeptiert db.BlobProperty.

Ich bin froh, dass jeder ein Codebeispiel (sowohl auf Client- als auch auf Serverseite) bereitstellen kann, wie dies getan werden kann.


@ user858915 Der Link ist defekt :(
Marco

Antworten:


44

Hier ist eine vollständige Arbeitsdatei. Ich habe das Original von der Google-Website abgerufen und geändert, um es etwas realer zu gestalten.

Ein paar Dinge zu beachten:

  1. Dieser Code verwendet die BlobStore-API
  2. Der Zweck dieser Zeile in der ServeHandler-Klasse besteht darin, den Schlüssel so zu "reparieren", dass alle im Browser möglicherweise aufgetretenen Namensverfälschungen beseitigt werden (in Chrome habe ich keine beobachtet).

    blob_key = str(urllib.unquote(blob_key))
    
  3. Die "save_as" -Klausel am Ende ist wichtig. Dadurch wird sichergestellt, dass der Dateiname beim Senden an Ihren Browser nicht beschädigt wird. Werde es los, um zu beobachten, was passiert.

    self.send_blob(blobstore.BlobInfo.get(blob_key), save_as=True)
    

Viel Glück!

import os
import urllib

from google.appengine.ext import blobstore
from google.appengine.ext import webapp
from google.appengine.ext.webapp import blobstore_handlers
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp.util import run_wsgi_app

class MainHandler(webapp.RequestHandler):
    def get(self):
        upload_url = blobstore.create_upload_url('/upload')
        self.response.out.write('<html><body>')
        self.response.out.write('<form action="%s" method="POST" enctype="multipart/form-data">' % upload_url)
        self.response.out.write("""Upload File: <input type="file" name="file"><br> <input type="submit" name="submit" value="Submit"> </form></body></html>""")

        for b in blobstore.BlobInfo.all():
            self.response.out.write('<li><a href="https://stackoverflow.com/serve/%s' % str(b.key()) + '">' + str(b.filename) + '</a>')

class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
    def post(self):
        upload_files = self.get_uploads('file')
        blob_info = upload_files[0]
        self.redirect('/')

class ServeHandler(blobstore_handlers.BlobstoreDownloadHandler):
    def get(self, blob_key):
        blob_key = str(urllib.unquote(blob_key))
        if not blobstore.get(blob_key):
            self.error(404)
        else:
            self.send_blob(blobstore.BlobInfo.get(blob_key), save_as=True)

def main():
    application = webapp.WSGIApplication(
          [('/', MainHandler),
           ('/upload', UploadHandler),
           ('/serve/([^/]+)?', ServeHandler),
          ], debug=True)
    run_wsgi_app(application)

if __name__ == '__main__':
  main()

Erstaunlich , dass das funktioniert für alle , außer für mich ... self.__uploadsin blobstore_handlerist , Nonewenn ich das versuchen.
Tim

49

Tatsächlich wird diese Frage in der App Egnine-Dokumentation beantwortet. Siehe ein Beispiel zum Hochladen von Benutzerbildern .

HTML-Code in <form> </ form>:

<input type = "file" name = "img" />

Python-Code:

Klasse Gästebuch (webapp.RequestHandler):
  def post (selbst):
    Gruß = Gruß ()
    if users.get_current_user ():
      greeting.author = users.get_current_user ()
    greeting.content = self.request.get ("content")
    avatar = self.request.get ("img")
    greeting.avatar = db.Blob (Avatar)
    greeting.put ()
    self.redirect ('/')

Dieser Ansatz gefällt Ihnen nicht, da Sie Informationen zum MIME-Typ verlieren.
Santiagobasulto

@ Santiagobasulto: Warum überprüfst du es nicht selbst?
Vietnam

Ich will es nicht überprüfen. Wenn Sie ein Bild anzeigen müssen, müssen Sie Informationen zum MIME-Typ angeben (unabhängig davon, ob es sich um JPG, GIF usw. handelt). Daher müssen Sie den HTTP-Header vom Inhaltstyp angeben. Wenn Sie das Bild mit der von Ihnen bereitgestellten Lösung hochladen, wissen Sie in Zukunft nicht mehr, welchen Inhaltstyp das Bild hat. Ergo können Sie den Header nicht festlegen. Ergo haben alte Browser Probleme, das Bild anzuzeigen. wegen des Fehlens des Inhaltstyps)
Santiagobasulto

1
Wenn Sie den MIME-Typ nicht überprüfen, dem Sie dem Client vertrauen, sind Sie offen für Black-Hat-Angriffe oder falsch konfigurierte MIME-Typen im Client. Wenn Sie dies tun möchten, können Sie einfach der Dateierweiterung selbst vertrauen.
Nacho Coloma



6

Ich versuche es heute, es funktioniert wie folgt:

meine sdk version ist 1.3.x.

HTML-Seite:

<form enctype="multipart/form-data" action="/upload" method="post" > 
<input type="file" name="myfile" /> 
<input type="submit" /> 
</form> 

Servercode:

file_contents = self.request.POST.get('myfile').file.read() 

3

Wenn Sie immer noch ein Problem haben, überprüfen Sie, ob Sie im Formular-Tag enctype verwenden

Nein:

<form encoding="multipart/form-data" action="/upload">

Ja:

<form enctype="multipart/form-data" action="/upload">

Ich habe einen Codierungsfehler erhalten, bevor ich Ihre Antwort implementiert habe
Jader Dias

1
Ein wirklich ärgerlicher Haken für mich, als ich das tat, war, "Größe" für den Dateieingabetyp nicht einzuschließen. Ich habe mit Safari getestet, das anscheinend standardmäßig eine sehr kurze Dateilänge hat (?), Und alles, was ich in GAE für den Inhalt der Datei erhielt, war der Name der Datei. Nur ein Wort der Warnung, das jemandem leichte Kopfschmerzen ersparen könnte.
John Carter

1

Sie können keine Dateien speichern, da es kein herkömmliches Dateisystem gibt. Sie können sie nur in ihrem eigenen DataStore speichern (in einem Feld, das als BlobProperty definiert ist ).

Im vorherigen Link gibt es ein Beispiel:

class MyModel(db.Model):
  blob = db.BlobProperty()

obj = MyModel()
obj.blob = db.Blob( file_contents )

1

Persönlich fand ich das hier beschriebene Tutorial nützlich, wenn ich die Java-Laufzeit mit GAE verwende. Aus irgendeinem Grund, als ich versuchte, eine Datei mit hochzuladen

<form action="/testservelet" method="get" enctype="multipart/form-data">
    <div>
        Myfile:<input type="file" name="file" size="50"/>
    </div>

    <div>
        <input type="submit" value="Upload file">
    </div>
</form>

Ich habe festgestellt, dass meine HttpServlet-Klasse aus irgendeinem Grund das Formular mit dem Attribut 'enctype' nicht akzeptiert. Das Entfernen funktioniert jedoch. Dies bedeutet, dass ich keine Dateien hochladen kann.


1
Dies kann daran liegen, dass Sie die get-Methode verwenden. Versuchen Sie stattdessen, sie auf post zu setzen. Ich bin nicht sicher, ob es funktionieren wird, aber es lohnt sich, es zu versuchen.
Slashnick

0

In Google App Engine wird keine Flatfile gespeichert. Alles muss in den Datenspeicher gehen, der ein bisschen wie eine relationale Datenbank ist, aber nicht ganz.

Sie können die Dateien als TextProperty- oder BlobProperty- Attribute speichern .

Es gibt eine Beschränkung von 1 MB für DataStore-Einträge, die möglicherweise ein Problem darstellen oder nicht.


So speichern Sie Dateien mit mehr als 1 MB. Ich benutze github.com/ckopanos/django-google-cloud-storage
Geo Jacob

0

Ich habe beim Hochladen von Dateien auf App Engine ein merkwürdiges Verhalten festgestellt. Wenn Sie das folgende Formular einreichen:

<form method="post" action="/upload" enctype="multipart/form-data">
    <input type="file" name="img" />
    ...
</form>

Und dann extrahieren Sie das imgaus der Anfrage wie folgt:

img_contents = self.request.get('img')

Die img_contentsVariable ist eine str()in Google Chrome, in Firefox jedoch Unicode. Und wie Sie jetzt nimmt der db.Blob()Konstruktor eine Zeichenfolge und gibt einen Fehler aus, wenn Sie eine Unicode-Zeichenfolge übergeben.

Weiß jemand, wie dies behoben werden kann?

Was ich absolut seltsam finde, ist, dass das Kopieren und Einfügen der Gästebuchanwendung (mit Avataren) perfekt funktioniert. Ich mache alles genauso in meinem Code, aber es wird einfach nicht funktionieren. Ich bin sehr nahe daran, mir die Haare auszureißen.


2
: D Das Formular lautete: mutlipart / form-data anstelle von multipart / form-data. Chrome ist klug genug, um den Tippfehler zu korrigieren, Firefox nicht.
Honza Pokorny

0

Es gibt eine Möglichkeit, ein Flat-File-System zu verwenden (zumindest in der Nutzungsperspektive).

Es gibt dieses virtuelle Dateisystemprojekt von Google App Engine . Dies wird mithilfe von Datenspeicher- und Memcache-APIs implementiert, um ein gewöhnliches Dateisystem zu emulieren. Mit dieser Bibliothek können Sie in Ihrem Projekt einen ähnlichen Dateisystemzugriff (Lesen und Schreiben) projizieren .

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.