【问题标题】:Updating content-type after file upload on Amazon S3 with Amazon-SDK Ruby gem使用 Amazon-SDK Ruby gem 在 Amazon S3 上上传文件后更新内容类型
【发布时间】:2016-05-27 16:05:06
【问题描述】:

我正在运行一个脚本,该脚本会在我的一些 S3 对象已上传到 S3 存储桶后更新它们的元数据字段。在初始化时,我通过检查文件名来设置内容类型。

def save_to_amazon(file, s3_object, file_name, meta_path)
  puts "uploaded #{file} to Amazon S3"
  content_type = set_content_type(file_name)
    s3_object.write(file.get_input_stream.read, :metadata => { :folders => meta_path}, :content_type => content_type)
end

此时,S3 内容类型适用于这些对象。当我稍后更新元数据时会出现问题。我运行这样的东西:

s3_object.metadata['folders'] = "some string"

此时,我在更新元数据后运行s3_objects.content_type 时返回一个空字符串。

s3_object.content_type = 不可用。

据我阅读Rdoc 可知,上传 S3 文件后无法分配内容类型。我尝试过使用元数据方法,例如

s3.object.metadata['content_type'] = "some string"
s3.object.metadata['content-type'] = "some string"

这两个似乎都分配了一个新的自定义元数据属性,而不是更新对象的 mime 类型。

有没有办法设置这个,还是我需要重新完全重新上传文件?

【问题讨论】:

    标签: ruby amazon-s3


    【解决方案1】:

    为了详细说明 tkotisis 响应,这是我使用 copy_to 更新内容类型所做的。您可以使用 s3object.head[:metadata] 提取现有的元数据以将其复制到引用的here

    amazon_bucket.objects.each do |ob|
        metadata = ob.head[:metadata]
        content_type = "foo/bar"
        ob.copy_to(ob.key, :metadata => metadata, :content_type => content_type)
    end
    

    编辑

    amazon_bucket.objects.each do |ob|
        metadata = ob.metadata
        content_type = "foo/bar"
        ob.copy_to(ob.key, :metadata{:foo => metadata[:foo]}, :content_type => content_type)
    end
    

    【讨论】:

      【解决方案2】:

      您的示例代码仅修改您的内存对象。 要修改实际 S3 对象的元数据,请发出复制请求,其中目标键是您当前对象之一。

      编辑

      根据documentation

      使用复制操作,您可以通过复制对象来重命名对象 删除原来的。

      复制对象时,您可能会决定更新一些 元数据值。例如,如果您的源对象配置为 使用标准存储,您可以选择使用减少冗余 对象副本的存储。您可能还决定更改一些 源对象上存在的用户定义的元数据值。笔记 如果您选择更新任何对象的用户可配置 复制期间的元数据(系统或用户定义),那么您必须 明确指定所有用户可配置的元数据,即使您是 仅更改源上存在的元数据值之一 请求中的对象。

      我没有尝试过,但是使用Ruby SDK这可能是通过

      - (S3Object) copy_to(target, options = {})
      

      method.

      【讨论】:

      • 我的存储桶中的文件似乎已更新。我可以稍后打电话给他们查看数据,或者进入管理控制台查看我刚刚在上面的代码中列出的所有内容。你能详细说明复制请求吗?
      • 感谢您为我指明了正确的方向。我刚刚发布了我能够整合的解决方案。
      【解决方案3】:

      我正在使用 gem "aws-sdk", "~> 2" (2.2.3)

      假设你有一个没有设置 content-type 的当前文件(Content-type 默认设置为“binary/octet-stream”)

      如何检查内容类型文件?

      如果你使用RestClient如下:

      对象表示 Aws::S3::Object

      bucket = Aws::S3::Bucket.new(bucket_name)
      object = bucket.object(key)
      
      RestClient.head(object.presigned_url(:head)) do |resp|
        puts resp.headers
        puts resp.headers[:content_type]
      end
      

      如何更改内容类型文件?

      就我而言,我想将内容类型更改为“图像/jpeg”,当前对象是“二进制/八位字节流”,以便您可以

      object.copy_from(
        object, 
        content_type: 'image/jpeg', 
        metadata_directive: 'REPLACE'
      )
      

      【讨论】:

      • 请注意,如果您使用metadata_directive: 'REPLACE',您应该复制所有现有的元数据值(即content_typemetadataexpire),否则它将用nil 值覆盖它们.在你的例子中:object.copy_from( object, object.data.to_h.slice(:metadata, :expires).merge({ content_type: 'image/jpeg', metadata_directive: 'REPLACE' }) )
      【解决方案4】:

      确保您将 ACL 设置为 :public read,否则您的文件在复制后将不可用。

      这对我有用:

      bucket.objects.with_prefix('my_assets').each do |obj|
        metadata = obj.head[:metadata]
        content_type = "application/pdf"
        obj.copy_to(obj.key, :metadata => metadata, :content_type => content_type)
        obj.acl = :public_read
      end
      

      【讨论】:

        【解决方案5】:

        虽然不是 Ruby,但我发现 this project 根据扩展名和重置自动猜测 mime 类型是通过其他答案所指的相同复制方法。它不是非常快,因为它必须复制 blob。如果你需要让它更快地发生,你可以通过 IronWorker 之类的东西来划分工作并并行复制。我做了一个similar thing for resetting permissions

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-05-07
          • 2011-04-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-11-05
          相关资源
          最近更新 更多