2014-05-23 18 views
6

Ich bin sicher, die Antwort auf diese Frage ist einfach, aber für mich ist es sehr frustrierend, da ich keine Lösung, die ich gefunden habe, in praktische Code für meine eigene Benutzung.Hochladen von Dateien in Google Cloud-Speicher von Appengine App

Ich baue eine App auf der App-Engine, mit der der Benutzer eine Datei hochladen kann, die dann von der App bearbeitet wird. Die Dateigröße beträgt in der Regel einige MB und in einigen Fällen bis zu 20 MB. Dies ist genug, um die 30-Sekunden-Zeitüberschreitung in der App-Engine auszulösen, und ich versuche daher, direkt in den Cloud-Speicher zu laden, wie auf verschiedenen Websites vorgeschlagen (einschließlich hier).

Der Upload Teil meiner Form sieht wie folgt aus:

<form name="convert" action="/transform" method="post" enctype="multipart/form-data"> 
    <input type="file" name="coords"> 
    <input type="submit" name="submit" value="Transform"> 
</form> 

Und die Prozedur sieht wie folgt aus (ich bin nur mit der App Engine anfangen, so entschuldigen, wenn dieser blöde aussieht

class TransformPage(BaseHandler): 
    def get(self): 
    self.render_template('transform.html',name=self.request.get('form')) 

    def post(self):  
     filename = self.request.POST['coords'].filename 
     filesize = int(self.request.headers['Content_Length']) 

     if filesize>5242880: 
      self.redirect('/error') 
     else: 
      save_to_cloud(file.value,filename) 
      # Start processing file here 
.

ich habe bei der Prüfung für die Dateigröße als eine sehr einfache Art und Weise den 30er Jahren Timeout zu verhindern, und 5Mb scheint die maximale Größe zu sein, die ich in 30s in meinem Netzwerk durchsetzen können.

die save_t o_cloud() ist nur ein Wrapper ich um die Google Cloud-Storage-API geschrieben hat, und sieht wie folgt aus:

def save_to_cloud(f,filename): 
    filename = BUCKET + filename               
    create_file_and_write(f,filename) 

Die vor allem Werke, und ich sehe die hochgeladenen Dateien in Cloud-Speicher zu landen, aber wie ich oben sagte , bricht für größere Dateien zusammen. Ich habe Hinweise zur Verwendung von create_upload_url gefunden, aber ich bin nicht gut genug, um zu sehen, wie das in meinem Fall aussieht, insbesondere den Inhalt der hochgeladenen Datei in den Speicher einzulesen, damit ich sie in den Cloud-Speicher schreiben kann.

Dies ist wahrscheinlich die einfachste Sache der Welt ist, wenn Sie wissen, wie es geht, aber ich kann es, ohne dass jemand nicht tun mir in Code zeigt, wie es :-(

Dank

getan werden kann

edit: @Itamar. das ist in der Tat, was ich zu tun versuche, obwohl das Upload-Formular auch ein paar andere Auswahl enthält vom Anwender vorgenommen werden ich habe jetzt geändert meinen Code zu diesem

class TransformPage(BaseHandler): 
    def get(self): 
     upload_url =blobstore.create_upload_url('/upload',gs_bucket_name='/my_bucket/') 


     self.render_template('transform.html', 
          {'name':self.request.get('form'),     
          {'upload_url':upload_url}) 

Aber ich kann Lass die upload_url nicht in der Vorlage html erscheinen, die ähnlich aussieht e dieses

<form name="convert" action="{{ upload_url }}" method="post" enctype="multipart/form-data"> 
+0

Sie können create_upload_url_async statt create_upload_url verwenden. Diese asynchrone Version kann eine Rückruffunktion übernehmen. Sie können das Dokument dazu sehen: https://developers.google.com/appengine/docs/python/blobstore/#Python_Making_asynchronous_requests – olituks

+0

Vielen Dank. Wie Sie jedoch aus meinen Code-Schnipsel oben sehen können, verwende ich create_upload_url nicht, da ich nicht verstehe, wie das in meinem Fall funktioniert (auch nach dem Lesen der Dokumente :-(In meinem Formular habe ich action = "/ transform ", die zu meinem Verständnis" die Form füttert ", zusammen mit der hochgeladenen Datei zu meinem def-Beitrag (selbst): Code in der Klasse TransformPage. – user3664865

Antwort

9

Wenn ich richtig verstehe, was Sie versuchen zu tun ist, eine Form von App Engine dienen, die ein Benutzer eine Datei auswählen können hochgeladen werden. Da die hochgeladene Datei möglicherweise groß ist, möchten Sie den Upload in App Engine nicht verarbeiten, sondern die Datei direkt in Google Cloud Storage hochladen.

Dies kann getan werden, und es ist nicht zu schwierig. In der Tat ist dies genau das Beispiel in der App Engine Python Blobstore docs gegeben. Es könnte verwirrend sein, dass sich das Beispiel auf Blobstore bezieht, während Sie die Datei in Cloud Storage wollen - aber es ist in Ordnung - es scheint, dass seit der Version 1.7.0 können Sie dies tun:

upload_url = blobstore.create_upload_url('/upload', gs_bucket_name='my_bucket') 

(anstelle von Schritt 1 in Das Beispiel, das ich verlinkt habe), und die Upload-URL wird direkt in Cloud Storage hochgeladen.

Nun sollte Ihre Formularaktion die Zeichenfolge upload_url sein, die von der blobstore.create_upload_url-Funktion zurückgegeben wurde.

Nachdem das Formular die Verarbeitung abgeschlossen hat (was bedeutet, dass die Datei hochgeladen wird), wird es auf das Argument umgeleitet, das Sie an diese Funktion übergeben haben (im Beispiel: /upload).

Sie müssen keine eigene POST-Verarbeitungsfunktion schreiben, wie Sie in der Frage beschrieben haben.

+0

Danke - das ist in der Tat, was ich versuche zu tun, obwohl in meiner Form habe ich Ich habe meine ursprüngliche Frage mit einigen Follow-up-Dingen bearbeitet! Danke nochmals – user3664865

+0

in Bezug auf das Follow-up, müssen Sie sicherstellen, dass Ihre App für die Arbeit mit GCS konfiguriert ist, und Beachten Sie, dass Ihr Aufruf von create_upload_url korrekt ist. Weitere Informationen finden Sie in den [Dokumenten für die Funktion] (https://developers.google.com/appengine/docs/python/blobstore/functions#create_upload_url) und in [Dokumentation zum Konfigurieren von GCS ] (https://developers.google.com/appengine/docs/python/blobstore/#Pyth on_Using_the_Blobstore_API_with_Google_Cloud_Storage). – Itamar

+0

Zusätzlich, um Template-Rendering-Probleme und API-Nutzungsprobleme zu trennen, schreiben Sie den Rückgabewert von 'create_upload_url', um zu protokollieren, und versuchen Sie es auch eine konstante Zeichenfolge zuweisen und überprüfen Sie, dass es im Formular gerendert wird. – Itamar

0

Ich habe einen Kern erstellt das zeigt, wie GCS-Dateien hochladen und verwenden: https://gist.github.com/voscausa/9541133

Dies ist der Code die mehrteiliger Form Post zu handhaben:

class GcsUpload(webapp2.RequestHandler): 

    def post(self): 

     field_storage = self.request.POST.get("file", None) 
     if isinstance(field_storage, cgi.FieldStorage): 
      file_name = field_storage.filename 

      dyn = gcs_data.Dynamics(id=file_name, filename=file_name) 
      gcs_file_name = gcs_data.gcs_write_blob(dyn, field_storage.file.read()) 
      gcs_data.gcs_serving_url(dyn) 
      dyn.put() 
      logging.info('Uploaded and saved in default GCS bucket : ' + gcs_file_name) 

      self.response.headers[b'Content-Type'] = gcs_data.gcs_content_type(dyn) 
      self.response.write(gcs_data.gcs_read_blob(dyn)) 

     else: 
      logging.error('GCS Upload failed') 
+0

Dies funktioniert nicht für Dateien über 32 MB. –

+0

JA. Ich zeige eine Alternative für kleine Dateien wie js, css und Bilder und ich zeige, wie man den content_type für utf-8-Dateien wie .css und .js setzt. Der Blobstore-Upload ignoriert diese utf-8-Inhaltsinformationen. Übrigens: Ich habe utf-8 für .css und .js Dateien in den Beispielen verwendet. – voscausa

+0

Bitte geben Sie das in Ihrer Antwort an. –

Verwandte Themen