在S3上设置Fog存储文件的内容类型

3
我正在使用Fog和Amazon s3来管理视频和图像文件。在设置文件的content_type时,我遇到了很多问题。
当在控制台上工作时,我可以逐个更新每个文件的content_type,然后运行保存操作。但是,当我尝试在特定目录中更新所有文件时,没有出现错误,但是没有任何更新。我运行了多种不同的方法,所有方法的基本思想都相同,并且都设置为在文件保存时打印“saved!”。这些方法正常运行并打印出“saved!”,但是当我回去检查文件时,发现content_type仍然为空。
以下是我的一个示例:
directory.files.each do |f|
  case f.key.split(".").last
  when "jpg"
    f.content_type = "image/jpeg"
    puts "saved!" if f.save
  when "mov"
    f.content_type = "video/quicktime"
    puts "saved!" if f.save
  end
end

此外,当我逐个更新每个文件时,保存工作正常,并且 content_type 得到了更新,但数据并没有持久化。例如:
file = directory.files.first
file.content_type = 'video/quicktime'
file.save         # returns true
file.content_type # returns 'video/quicktime'

然而,当我在AWS中检查文件时,内容类型仍为空。
有没有更好(持久)的方法来更新Fog s3文件上的content_type?我觉得我一定是走错了路。
更新: 尝试使用file#copy方法:
directory.files.each do |f|
  content_type = case f.key.split(".").last
  when "jpg"
    "image/jpeg"
  when "mov"
    "video/quicktime"
  end
  puts "copied!" if f.copy(f.directory.key, f.key, { 'Content-Type' => content_type })
end

我收到了一个错误提示:

Excon::Errors::BadRequest: Expected(200) <=> Actual(400 Bad Request)

from /Users/marybethlee/.rvm/gems/ruby-2.0.0-p0@mothership/gems/excon-0.22.1/lib/excon/middlewares/expects.rb:6:in `response_call'
from /Users/marybethlee/.rvm/gems/ruby-2.0.0-p0@mothership/gems/excon-0.22.1/lib/excon/connection.rb:355:in `response'
from /Users/marybethlee/.rvm/gems/ruby-2.0.0-p0@mothership/gems/excon-0.22.1/lib/excon/connection.rb:249:in `request'
from /Users/marybethlee/.rvm/gems/ruby-2.0.0-p0@mothership/gems/fog-1.11.1/lib/fog/core/connection.rb:21:in `request'
from /Users/marybethlee/.rvm/gems/ruby-2.0.0-p0@mothership/gems/fog-1.11.1/lib/fog/aws/storage.rb:506:in `request'
from /Users/marybethlee/.rvm/gems/ruby-2.0.0-p0@mothership/gems/fog-1.11.1/lib/fog/aws/requests/storage/copy_object.rb:33:in `copy_object'
from /Users/marybethlee/.rvm/gems/ruby-2.0.0-p0@mothership/gems/fog-1.11.1/lib/fog/aws/models/storage/file.rb:93:in `copy'
from (irb):14
from /Users/marybethlee/.rvm/rubies/ruby-2.0.0-p0/bin/irb:16:in `<main>'
2个回答

6
如果您只是更新元数据(而不是正文/内容本身),您可能希望使用复制而不是保存。这可能不是很明显,但这样可以使操作保持在S3侧,从而速度会更快。
复制的签名如下:
`copy(target_directory_key, target_file_key, options = {})`
因此,我认为我的建议解决方案应该看起来像这样:
directory.files.each do |f|
  content_type = case f.key.split(".").last
  when "jpg"
    "image/jpeg"
  when "mov"
    "video/quicktime"
  end
  options = {
    'Content-Type' => content_type,
    'x-amz-metadata-directive' => 'REPLACE'
  }
  puts "copied!" if f.copy(f.directory, f.key, options)
end

那基本上告诉 S3 "复制我的文件并更改此头文件"。这样,您就不必下载/重新上传文件了。这可能是您想要的方法。
因此,解决方案搁置一旁,似乎仍然存在错误。您能否提供“单独更新每个文件”的示例?只是想确保我确切地知道您的意思,并且可以将工作/非工作案例并排显示。此外,您认为它为什么/如何没有更新内容类型(它实际上可能正在更新它,但只是没有正确显示更新后的值或类似的东西)。如果您能在此处创建问题,以确保我不会忘记解决它,则可以获得额外的积分:https://github.com/fog/fog/issues?state=open

所以我尝试了你建议的方法,但是出现了错误: Excon::Errors::BadRequest: Expected(200) <=> Actual(400 Bad Request) 我会编辑我的原始帖子,包括这个错误以及我所说的单独更新的示例。 - oolong
1
啊哈!是的,指定替换修复了错误,但仍然是我之前遇到的同样问题。通过循环打印出已复制,但所有文件的内容类型仍为nil,逐个更新它们似乎有效,但没有传输到aws。 - oolong
那么,为了澄清一下。您发出请求并且似乎成功了,您是如何查找返回nil的内容类型的?您是在执行 files.all.each {|file| file.content_type} 还是 files.get(key).content_type 或者其他操作?只是想确保我知道那边的情况(因为它可能在S3上设置了但在客户端上没有正确更新/显示)。特别是当执行 files.all 时,默认情况下不包括此信息。 - geemus
你说得对。如果我执行 directory.files.first.content_type,会返回 nil。但是如果我将同一个文件的 key 传递给 directory.files.get(key).content_type,它会返回 "video/quicktime"。这是 S3 相关的问题吗,还是根本不是问题?既然知道了发生了什么,我现在可以处理它了。 - oolong
这是一个与S3相关的限制/问题。你使用的API调用获取单个文件(而不是获取文件列表)返回略有不同的结果,你可能已经知道了。不幸的是,文件列表版本不包括太多元数据(你可以在这里完整地查看它所包含的内容:http://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketGET.html)。因此,那些信息在那里是无法访问的。 - geemus
显示剩余5条评论

0

我找到了一个解决方法来获取内容类型:

directory.files.head(file.key).content_type

其中file.key是您文件的名称。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接