如何生成临时URL以使用boto库将文件上传到Amazon S3?

时间:2012-04-06 13:28:31

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

我知道如何以这种方式下载文件 - key.generate_url(3600)。

但是当我尝试上传:key.generate_url(3600,method ='PUT')时,网址无效。有人告诉我:   “我们计算的请求签名与您提供的签名不符。请检查您的密钥和签名方法。”

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

5 个答案:

答案 0 :(得分: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将文件PUT到该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来完成这项工作,但我还没有尝试过。

答案 1 :(得分:26)

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

首先,使用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'

使用预先签名的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"

答案 2 :(得分:11)

所有其他答案都假定文件将与curl一起上传,这在大多数python脚本中都不方便。在下面,使用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())

答案 3 :(得分:9)

这是4月6日至12月4日回答garnaat的回复。

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

我能够在没有指定标题中的内容长度或指定force_http = True的情况下获取PUT方法的签名URL。

使用Boto 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产生的相比,请求增加了一些额外的头文件。

我希望这个后续回答能够让别人感受到我经历过的调试痛苦。

答案 4 :(得分:0)

如果您使用的是boto(而不是boto3),那么我能够上载的唯一方法是使用generate_url_sigv4。使用香草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