2012-04-06 3 views
19

Ich wusste, wie man Datei auf diese Weise herunterladen - key.generate_url (3600).Wie erstelle ich eine temporäre URL, um eine Datei mit Boto Library auf Amazon S3 hochzuladen?

Aber als ich versuchte zu laden: key.generate_url (3600, Methode = 'PUT'), die URL hat nicht funktioniert. Mir wurde gesagt: "Die von uns berechnete Anforderungssignatur stimmt nicht mit der von Ihnen angegebenen Signatur überein. Überprüfen Sie Ihren Schlüssel und die Signaturmethode."

Ich kann Beispiel Code in Boto homepage nicht finden, wie man die Funktion generate_url (method = 'PUT') benutzt. Kennt jemand hier, wie man es für das Hochladen benutzt? Wie setze ich die Parameter für den Pfad der Upload-Datei?

+0

Ist das eine neue Datei? Um eine neue Datei zu erstellen, sollten Sie 'POST', nicht' PUT' verwenden. – vartec

+0

@vartec: Was meinen Sie mit "eine neue Datei"? In meinem Anwendungsfall muss ich manchmal einen neuen Schlüssel in einen bestimmten Bucket hochladen, manchmal muss ich den alten Schlüssel überschreiben. Ich denke, ich brauche das Codebeispiel für 'PUT' und 'POST'. –

Antwort

40

Ich habe etwas Zeit gefunden, damit zu experimentieren und hier ist, was ich gefunden habe.

>>> import boto 
>>> c =boto.connect_s3() 
>>> fp = open('myfiletoupload.txt') 
>>> content_length = len(fp.read()) 
>>> c.generate_url(300, 'PUT', 'test-1332789015', 'foobar', headers={'Content-Length': str(content_length)}, force_http=True) 
'http://test-1332789015.s3.amazonaws.com/foobar?Signature=oUARG45mR95utXsiQYRJNiCI4x4%3D&Expires=1333731456&AWSAccessKeyId=AKIAJOTCCJRP4C3NSMYA&Content-Length=16' 

war ich dann in der Lage curl zu verwenden, um die Datei zu dieser URL wie folgt ausgedrückt:

$ curl --request PUT --upload-file myfiletoupload.txt "http://test-1332789015.s3.amazonaws.com/foobar?Signature=oUARG45mR95utXsiQYRJNiCI4x4%3D&Expires=1333731456&AWSAccessKeyId=AKIAJOTCCJRP4C3NSMYA&Content-Length=16" 

Dieser in der Datei geführt, um die Eimer hochgeladen werden. So scheint es, dass es möglich ist. Vielleicht möchten Sie sehen, ob Sie den Content-MD5-Wert berechnen und in die Header aufnehmen können, aber dann müssen Sie auch herausfinden, wie man curl erhält, um diesen Header zu senden. Außerdem sollten Sie in der Lage sein, dies über HTTPS statt HTTP zu machen, aber ich habe das nicht versucht.

+0

Es funktioniert, vielen Dank! –

+2

'Header'-Argument in dieser Antwort wird jetzt nicht funktionieren, wird es" Signatur nicht übereinstimmen "Fehler beim Hochladen verursachen. Wenn Sie Header * in der Antwort * angeben wollen, wenn Sie die Datei später holen, müssen Sie 'response_headers' verwenden und die Felder wie' response-content-type' usw. verwenden. – MLister

+0

Getestet auf Google Cloud Storage, aber fehlgeschlagen. Würde es Ihnen etwas ausmachen, sich diese Frage anzusehen? Vielen Dank. http://stackoverflow.com/questions/38938203/django-heroku-boto-direct-file-upload-to-google-cloud-storage –

8

Dies ist eine Folge von Garnaats Antwort vom 6. April 12.

Ich erstelle eine signierte URL-Server-Seite, wo ich Anmeldeinformationen habe, und ich übergebe es an einen Client, so dass ein Client Inhalte direkt hochladen kann. Ich vertraue dem Client so weit, dass er Dateien beliebiger Größe hochladen kann, aber nicht genug, um Sicherheitstoken zu geben. Ich wollte vermeiden, dass der Client dem Server mitteilt, wie groß sein Inhalt als Teil der Anfrage wäre. Daher meine Follow-up-Antwort.

Ich konnte die signierte URL für die PUT-Methode arbeiten, ohne die Inhaltslänge in den Headern anzugeben oder force_http = True anzugeben.

Mit Boto 2.31.1: wie in answere der garnaat:

>>> import boto 
>>> c =boto.connect_s3() 

dann stattdessen verwendet I:

>>> temp_url = c.generate_url(seconds_available, 'PUT', bucket_name, s3_key) 

dies eine URL in der folgenden Form erzeugt:

https://s3_location/bucket_name/s3_key?Signature=Ew407JMktSIcFln%2FZe00VroCmTU%3D&Expires=1405647669&AWSAccessKeyId=kM__pEQo2AEVd_Juz4Qq 

Ich konnte dann curl verwenden, um eine Datei zu posten:

>>> os.system('curl --request PUT --upload-file true_measure/test_files/test_file_w_content.txt "'+temp_url+'"') 

Ich hatte eine sehr schwierige Zeit herauszufinden, weil ich normalerweise python requests verwenden, um Tests zu schreiben und zu debuggen; Ich erhalte jedoch einen Fehler bei der Authentifizierung, wenn ich versuche, eine Datei mithilfe von Anfragen an eine dieser boto-generierten signierten URLs zu senden. Ich habe das Problem noch nicht vollständig gelöst, aber ich vermute, dass dies darauf zurückzuführen ist, dass Anfragen einige zusätzliche Header hinzufügen, verglichen mit dem, was curl produziert.

Ich hoffe, diese Follow-up-Antwort schont jemand anderen den Debugging-Schmerz, den ich durchgemacht habe.

17

So sieht es in boto3 aus (getestet mit Version 1.2.3).

zunächst eine presigned URL mit s3.generate_presigned_url Methode erstellen:

>>> import boto3 
>>> s3 = boto3.client('s3') 
>>> s3.generate_presigned_url('put_object', Params={'Bucket':'YourBucket', 'Key':'YourKey'}, ExpiresIn=3600, HttpMethod='PUT') 
u'https://s3-ap-northeast-1.amazonaws.com/YourBucket/YourKey?AWSAccessKeyId=AKIAXXXXXXXXXXXXXXXX&Expires=1451061671&Signature=%2FtyAyCd5vrp13p%2FqLdoPkox7yTM%3D' 

PUT bis S3 mit einem presigned URL

$ curl \ 
    --request PUT \ 
    --upload-file path/to/file \ 
    "https://s3-ap-northeast-1.amazonaws.com/YourBucket/YourKey?AWSAccessKeyId=AKIAXXXXXXXXXXXXXXXX&Expires=1451061671&Signature=%2FtyAyCd5vrp13p%2FqLdoPkox7yTM%3D" 
+0

Wie fügen Sie Ihre Anmeldeinformationen, z. B. AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY? – CpILL

+1

@CPILL Sie können Anmeldeinformationen über Umgebungsvariablen übergeben. z. B. $ export AWS_ACCESS_KEY_ID = AKIAIOSFODNN7EXAMPLE http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html#clientation – quiver

+0

große Antwort, danke! –

9

Alle anderen Antworten der Datei übernehmen wird mit curl hochgeladen werden, was wirklich nicht bequem in den meisten Python-Skripten. Im Folgenden wird eine Pre-signierte URL generierte mit boto3 und die Datei mit der requests Bibliothek hochgeladen:

session = boto3.Session(aws_access_key_id="XXX", aws_secret_access_key="XXX") 
s3client = session.client('s3') 
url = s3client.generate_presigned_url('put_object', Params={'Bucket': 'mybucket', 'Key': 'mykey'}) 

requests.put(url, data=open("/path/to/file").read())