【问题标题】:Upload to Amazon S3 using Boto3 and return public url使用 Boto3 上传到 Amazon S3 并返回公共 url
【发布时间】:2015-11-19 16:40:39
【问题描述】:

我正在尝试使用 Boto3 将文件上传到 s3 并将上传的文件公开并将其作为 url 返回。

class UtilResource(BaseZMPResource):
class Meta(BaseZMPResource.Meta):
    queryset = Configuration.objects.none()
    resource_name = 'util_resource'
    allowed_methods = ['get']

def post_list(self, request, **kwargs):

    fileToUpload = request.FILES
    # write code to upload to amazone s3
    # see: https://boto3.readthedocs.org/en/latest/reference/services/s3.html


    self.session = Session(aws_access_key_id=settings.AWS_KEY_ID,
                  aws_secret_access_key=settings.AWS_ACCESS_KEY,
                  region_name=settings.AWS_REGION)

    client = self.session.client('s3')
    client.upload_file('zango-static','fileToUpload')


    url = "some/test/url"
    return self.create_response(request, {
        'url': url // return's public url of uploaded file 
    })

我搜索了整个文档,但找不到任何描述如何执行此操作的链接,有人可以解释或提供任何可以找到灵魂的资源吗?

【问题讨论】:

  • 你在哪里可以得到这个工作?
  • @nadermx 我无法完成这项工作,你能帮帮我吗?
  • 使用虚拟托管风格的 S3 url:stackoverflow.com/a/56090535/795876

标签: django-models amazon-s3 boto3


【解决方案1】:

我也有同样的情况。 除了 generate_presigned_url 之外,在 Boto3 文档中找不到任何东西,这不是我需要的,因为我有公共可读的 S3 对象。

我想出的最好的是:

bucket_location = boto3.client('s3').get_bucket_location(Bucket=s3_bucket_name)
object_url = "https://s3-{0}.amazonaws.com/{1}/{2}".format(
    bucket_location['LocationConstraint'],
    s3_bucket_name,
    key_name)

您可以尝试在boto3 github issues list 上发帖以获得更好的解决方案。

【讨论】:

  • 原来我不需要 URL 中的区域。 https://s3.amazonaws.com/my_bucket/my_file.jpg 为我工作。
  • @KimberlyW 这是因为您的资产所在区域是 US-EAST1 docs.aws.amazon.com/general/latest/gr/rande.html#s3_region
  • 如果文件包含非 ascii 和空格,则此答案不起作用。
  • 这个答案也不适用于与 localstack 的集成测试。
  • 这仍然是最好的解决方案吗?
【解决方案2】:

我找到的最佳解决方案仍然是使用generate_presigned_url,只是需要将Client.Config.signature_version 设置为botocore.UNSIGNED。

以下返回没有签名内容的公共链接。

config = Config(signature_version=botocore.UNSIGNED)
config.signature_version = botocore.UNSIGNED
boto3.client('s3', config=config).generate_presigned_url('get_object', ExpiresIn=0, Params={'Bucket': bucket, 'Key': key})

关于boto3仓库的相关讨论有:

【讨论】:

  • 这应该是公认的答案。例如,如果文件名包含空格,则同样敏锐的答案会中断,然后 key_name = object_url 的启发式会带有一些前缀中断。
  • 但它的有效期很短。最多只有 7 天,STS 的时间更短。
  • 为了使答案更加清晰,最好显示 config 的来源。示例:config = Config(signature_version=botocore.UNSIGNED) url = s3_session.client('s3', config=config).generate_presigned_url( ClientMethod='get_object', ExpiresIn=0, Params={'Bucket': bucket_name, 'Key': key} )
  • 根据您的建议编辑答案
  • 只要config = Config(signature_version=botocore.UNSIGNED) 就足够了。不需要第二行
【解决方案3】:

我有同样的问题。 假设您知道要存储数据的存储桶名称,则可以使用以下内容:

import boto3
from boto3.s3.transfer import S3Transfer

credentials = { 
    'aws_access_key_id': aws_access_key_id,
    'aws_secret_access_key': aws_secret_access_key
}

client = boto3.client('s3', 'us-west-2', **credentials)
transfer = S3Transfer(client)

transfer.upload_file('/tmp/myfile', bucket, key,
                     extra_args={'ACL': 'public-read'})

file_url = '%s/%s/%s' % (client.meta.endpoint_url, bucket, key)

【讨论】:

  • 谢谢,upload_file 中使用 S3Transfer 的 extra_args 是我在通过会话为自定义端点创建客户端时需要结合使用的。
  • 如何上传文件对象
  • @NomanGul 该链接没有解释如何在内存中上传对象并从中生成公共 URL
【解决方案4】:

有人想为公共可访问对象建立一个直接 URL 以避免出于某种原因使用 generate_presigned_url。

考虑到空格和特殊字符问题,请使用urllib.parse.quote_plus 构建 URL。

  • 我的对象键:2018-11-26 16:34:48.351890+09:00.jpg 请注意空格和':'
  • AWS 控制台中的 S3 公共链接:https://s3.my_region.amazonaws.com/my_bucket_name/2018-11-26+16%3A34%3A48.351890%2B09%3A00.jpg

下面的代码对我来说没问题

import boto3    
s3_client = boto3.client
bucket_location = s3_client.get_bucket_location(Bucket='my_bucket_name')
url = "https://s3.{0}.amazonaws.com/{1}/{2}".format(bucket_location['LocationConstraint'], 'my_bucket_name', quote_plus('2018-11-26 16:34:48.351890+09:00.jpg')
print(url)

【讨论】:

    【解决方案5】:

    通过现有的答案和他们的 cmets,我做了以下工作,并且适用于文件名的特殊情况,例如具有 空格、具有 特殊字符 (ASCII)、 极端案例。例如。格式的文件名:“key=value.txt”

    import boto3
    import botocore
    
    config = botocore.client.Config(signature_version=botocore.UNSIGNED)
    object_url = boto3.client('s3', config=config).generate_presigned_url('get_object', ExpiresIn=0, Params={'Bucket': s3_bucket_name, 'Key': key_name})
    print(object_url)
    

    【讨论】:

      【解决方案6】:

      对于 Django,如果您将 Django 存储与 boto3 一起使用,则以下代码完全符合您的要求:

      default_storage.url(name=f.name)
      

      【讨论】:

        【解决方案7】:

        我用了一个 f-string 来做同样的事情

        import boto3    
        #s3_client = boto3.session.Session(profile_name='sssss').client('s3')
        s3_client=boto3.client('s3')
        s3_bucket_name = 'xxxxx'
        s3_website_URL= f"http://{s3_bucket_name}.s3-website.{s3_client.get_bucket_location(Bucket=s3_bucket_name)['LocationConstraint']}.amazonaws.com"
        

        【讨论】:

          猜你喜欢
          • 2021-04-27
          • 1970-01-01
          • 1970-01-01
          • 2021-09-29
          • 2011-11-28
          • 2017-06-13
          • 2014-12-23
          • 2020-02-19
          相关资源
          最近更新 更多