23

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

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

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

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

  • как добавить свои учетные данные, например AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY?

    от
  • headers Аргумент в этом ответе теперь не будет работать, он вызовет ошибку «несоответствие подписи» при загрузке. Если вы хотите указать заголовкиin the response когда вы получите файл позже, вам нужно использоватьresponse_headers и используйте такие поля, какresponse-content-type и т.п.

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

    от
  • Спасибо за показ, как это сделать вboto3, В настоящее время переносится код изboto вboto3 и желаю, чтобы их документы были яснее обо всех изменениях.

    от
  • @CpILL Вы можете передавать учетные данные через переменные окружения. например, $ export AWS_ACCESS_KEY_ID = AKIAIOSFODNN7EXAMPLEdocs.aws.amazon.com/cli/latest/userguide/…

    от
  • отличный ответ, спасибо!

    от
  • Проверено на Google Cloud Storage, но не прошло. Не могли бы вы взглянуть на этот вопрос? Благодарю.stackoverflow.com/questions/38938203/…

    от
  • Это работает, спасибо большое!

    от michael.luk
  • Это новый файл? Чтобы создать новый файл, вы должны использоватьPOSTнеPUT

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

    от michael.luk
  • 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())
    

  • 25

    Вот как это выглядит в boto3 (протестировано с версией 1.2.3).

    Сначала создайте предопределенный 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"
    

  • 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, но я не пробовал это.

  • 9

    Это продолжение ответа от garnaat от 6 апреля 12.

    Я создаю подписанный 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.

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