Вопрос по python – Как создать временный URL для загрузки файла в Amazon S3 с помощью библиотеки boto?

23

Я знал, как скачать файл таким способом - key.generate_url (3600).

Но когда я попытался загрузить: key.generate_url (3600, method = 'PUT'), URL не работал. Мне сказали:   & quot; Рассчитанная нами подпись запроса не соответствует предоставленной вами подписи. Проверьте свой ключ и метод подписи. & Quot;

Я не могу найти пример кода на домашней странице boto, чтобы узнать, как использовать функцию generate_url (method = 'PUT'). Кто-нибудь здесь знает, как использовать его для загрузки? Как установить параметры для пути загрузки файла?

Это новый файл? Чтобы создать новый файл, вы должны использоватьPOSTнеPUT vartec
@vartec: Что значит «новый файл»? В моем случае использования иногда мне нужно загрузить новый ключ в определенную корзину, иногда мне нужно перезаписать старый ключ. Поэтому я думаю, что мне нужен пример кода для "PUT" и "POST". michael.luk

Ваш Ответ

4   ответа
25

Сначала создайте предопределенный URL сs3.generate_presigned_url метод:

>>> 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 to S3 с заданным 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"
как добавить свои учетные данные, например AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY?
отличный ответ, спасибо!
@CpILL Вы можете передавать учетные данные через переменные окружения. например, $ export AWS_ACCESS_KEY_ID = AKIAIOSFODNN7EXAMPLEdocs.aws.amazon.com/cli/latest/userguide/…
Спасибо за показ, как это сделать вboto3, В настоящее время переносится код изboto вboto3 и желаю, чтобы их документы были яснее обо всех изменениях.
9

Я создаю подписанный URL-адрес на стороне сервера, где у меня есть учетные данные, и я передаю его клиенту, чтобы клиент мог напрямую загружать контент. Я доверяю клиенту достаточно далеко, чтобы позволить ему загружать файлы произвольного размера, но недостаточно, чтобы предоставить ему токены безопасности. Я хотел, чтобы клиент не говорил серверу, насколько большим будет его содержимое в рамках запроса. Отсюда мой ответ.

Мне удалось получить подписанный URL-адрес для метода PUT, работающего без указания длины содержимого в заголовках или указания force_http = True.

Используя Boto 2.31.1: как в ответе гарнаата:

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

тогда вместо этого я использовал:

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

это произвело URL в следующем виде:

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

Затем я смог использовать curl для публикации файла:

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

Мне было очень трудно понять это, потому что я обычно используюзапросы Python писать тесты и отлаживать; однако я получаю ошибку аутентификации, когда пытаюсь использовать ее, чтобы поместить файл в один из этих сгенерированных boto подписанных URL, используя запросы. Я не полностью отладил это, но подозреваю, что это связано с тем, что запросы добавляют несколько дополнительных заголовков по сравнению с тем, что создает curl.

Я надеюсь, что следующий ответ избавит кого-то еще от отладочной боли, через которую я прошел.

os.system - это очень плохой способ взаимодействия с пользовательскими переменными
44

>>> 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'

Затем я смог использовать curl, чтобы положить файл на этот URL, как это:

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

Это привело к загрузке файла в корзину. Итак, похоже, что это возможно. Возможно, вы захотите узнать, можете ли вы рассчитать значение content-md5 и включить его в заголовки, но тогда вам также придется выяснить, как получить curl для отправки этого заголовка. Кроме того, вы должны быть в состоянии заставить это работать через HTTPS, а не HTTP, но я не пробовал это.

Это работает, спасибо большое! michael.luk
Проверено на Google Cloud Storage, но не прошло. Не могли бы вы взглянуть на этот вопрос? Благодарю.stackoverflow.com/questions/38938203/…
headers Аргумент в этом ответе теперь не будет работать, он вызовет ошибку «несоответствие подписи» при загрузке. Если вы хотите указать заголовкиin the response когда вы получите файл позже, вам нужно использоватьresponse_headers и используйте такие поля, какresponse-content-type и т.п.
10

curl, что на самом деле не удобно в большинстве сценариев Python. В последующем предварительно подписанный URL создается сboto3 и файл загружен сrequests библиотека:

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())

Похожие вопросы