【问题标题】:How to generate a temporary url to upload file to Amazon S3 with boto library?如何使用 boto 库生成临时 url 以将文件上传到 Amazon S3?
【发布时间】:2012-04-20 02:39:38
【问题描述】:

我知道如何通过这种方式下载文件:key.generate_url(3600)

但是当我尝试上传:key.generate_url(3600, method='PUT') 时,该网址不起作用。有人告诉我: The request signature we calculated does not match the signature you provided. Check your key and signing method.

我在boto 主页上找不到有关如何使用函数generate_url(method='PUT') 的示例代码。这里有人知道如何使用它进行上传吗?如何设置上传文件的路径参数?

【问题讨论】:

  • 这是一个新文件吗?要创建新文件,您应该使用POST,而不是PUT
  • @vartec:“新文件”是什么意思?在我的用例中,有时我需要将新密钥上传到某个存储桶,有时我需要覆盖旧密钥。所以我想我需要'PUT'和'POST'的代码示例。

标签: python amazon-s3 amazon-web-services boto


【解决方案1】:

我找到了一些时间来试验这个,这就是我发现的。

>>> 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 进行这项工作,但我还没有尝试过。

【讨论】:

  • headers 此答案中的参数现在不起作用,上传时会导致“签名不匹配”错误。如果你想在以后获取文件时在响应中指定headers,需要使用response_headers,并使用response-content-type等字段。
  • 在 Google Cloud Storage 上测试但失败。你介意看看这个问题吗?谢谢。 stackoverflow.com/questions/38938203/…
【解决方案2】:

这是在 boto3 中的样子(使用 1.2.3 版测试)。

首先,使用s3.generate_presigned_url方法创建一个预签名的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'

使用预签名的 URL 将其放入 S3

$ 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=AKIAIOSFODNN7EXAMPLE docs.aws.amazon.com/cli/latest/userguide/…
  • 感谢您在boto3 中展示如何操作。目前正在将代码从 boto 迁移到 boto3,并希望他们的文档对所有更改都更加清晰。
  • 我在这个问题上花了 21 个小时,直到我终于看到了这段代码。谢谢。文档以一种令人难以置信的方式吸吮。很高兴找到一个经历过同样地狱并通过另一边胜利的人。
【解决方案3】:

所有其他答案都假定文件将使用curl 上传,这在大多数 python 脚本中确实不方便。下面,使用boto3 生成一个预签名的url,并使用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())

【讨论】:

  • 分散在 SO 中的其他解决方案使用 'rb' 和 post。他们对我不起作用,但这个对我有用
【解决方案4】:

这是对 garnaat 2012 年 4 月 6 日的回答的跟进。

我正在生成一个签名的 URL 服务器端,我有凭据,并将其传递给客户端,以便客户端可以直接上传内容。我足够信任客户端以允许它上传任意大小的文件,但不足以为其提供安全令牌。我想避免让客户端告诉服务器其内容作为请求的一部分有多大。因此我的后续回答。

我无需在标头中指定内容长度或指定 force_http=True 即可获得 PUT 方法的签名 url。

使用博托 2.31.1: 正如 garnaat 的回答:

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

然后我使用了:

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

这产生了以下形式的网址:

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 requests 来编写测试和调试;但是,当我尝试使用它将文件放入这些 boto 使用请求生成的签名 url 之一时,我遇到了身份验证失败。我还没有完全调试这个,但我怀疑这是因为与 curl 产生的相比,请求添加了一些额外的标题。

我希望这个后续回答可以减轻其他人的调试痛苦。

【讨论】:

  • os.system 只是与自定义变量交互的一种非常糟糕的方式
【解决方案5】:

如果您使用的是 boto(不是 boto3),我能够上传文件的唯一方法是使用 generate_url_sigv4。使用 vanilla generate_url 导致与原始问题中报告的错误相同。可能有一个我不知道的 AWS 帐户设置控制哪个功能起作用。

在带有 boto 2.49.0 并请求 2.22.0 的 Python 解释器中:

import boto
import os
import requests
os.environ['S3_USE_SIGV4'] = 'True'
c = boto.connect_s3(host='s3.amazonaws.com')
url = c.generate_url_sigv4(3600, 'PUT', 'my-bucket-name', 'bucket-path/to/file.txt')
with open('file.txt') as f:
    resp = requests.put(url, data=f.read())

>>> resp
<Response [200]>

如果您不使用主机名连接,则在生成 URL 时会收到此错误:

boto.s3.connection.HostRequiredError: BotoClientError: When using SigV4, you must specify a 'host' parameter.

相关:
What does ''HmacAuthV1Handler' object has no attribute 'presign'' mean?

如果您使用的是 boto3,预签名的 POST 似乎有更好的文档记录:
https://boto3.amazonaws.com/v1/documentation/api/latest/guide/s3-presigned-urls.html#generating-a-presigned-url-to-upload-a-file

【讨论】:

    猜你喜欢
    • 2014-12-16
    • 1970-01-01
    • 1970-01-01
    • 2011-03-25
    • 1970-01-01
    • 2012-12-28
    • 2017-08-18
    • 1970-01-01
    • 2012-01-11
    相关资源
    最近更新 更多