1

是否可以在用户右键单击 + 保存为 Carrierwave + S3 + Heroku + Content-Disposition 之前重命名文件名?我正在考虑在将文件保存在 S3 服务器上之前清理文件名(例如 193712391231.flv),并将原始文件名保存在数据库的列中。

当用户决定下载文件时(右键单击并另存为)。我无法将其作为 193712391231.flv 提供/发送。相反,我想发送带有原始文件名的文件。

如何实施?

使用载波。我遇到过这个:

uploaded = Video.first.attachment
uploader.retrieve_from_store!(File.basename(Video.first.attachment.url))
uploader.cache_stored_file!

send_file uploader.file.path

这不会由 S3 提供,因为它首先将文件缓存在本地文件系统中,然后将其发送到浏览器。它占用了整个网络进程(Heroku 中的 Dyno)。

如果有人有任何想法,请提出建议。

4

2 回答 2

3

阿克舒利,您可以:

# minimal example, 
# here using mongoid, but it doesn't really matter

class Media 

  field :filename, type: String   # i.e. "cute-puppy"
  field :extension, type: String  # i.e. "mp4"

  mount_uploader :media, MediaUploader

end

class MediaUploader < CarrierWave::Uploader::Base

  # Files on S3 are only accessible via signed URLS:
  @fog_public = false 

  # Signed URLS expire after ...:
  @fog_authenticated_url_expiration = 2.hours # in seconds from now, (default is 10.minutes)

  # MIME-Type and filename that the user will see:
  def fog_attributes
    {
      "Content-Disposition" => "attachment; filename*=UTF-8''#{model.filename}",
      "Content-Type" => MIME::Types.type_for(model.extension).first.content_type
    }
  end

  # ...
end

然后产生的 urlmodel.media.url将返回以下标头:

Accept-Ranges:bytes
Content-Disposition:attachment; filename*=UTF-8''yourfilename.mp4
Content-Length:3926746
Content-Type:video/mpeg
Date:Thu, 28 Feb 2013 10:09:14 GMT
Last-Modified:Thu, 28 Feb 2013 09:53:50 GMT
Server:AmazonS3
...

然后浏览器将强制下载(而不是在浏览器中打开)并使用您设置的文件名,而不管用于在存储桶中存储内容的文件名是什么。唯一的缺点是 Content-Disposition 标头是在 Carrierwave 创建文件时设置的,因此您不能例如在同一个文件上为不同的用户使用不同的文件名。

在这种情况下,您可以使用 RightAWS 生成签名 URL:

class Media

  def to_url 
    s3_key = "" # the 'path' to the file in the S3 bucket

    request_header = {}
    response_header = {
      "response-content-disposition" => "attachment; filename*=UTF-8''#{filename_with_extension}",
      "response-content-type" => MIME::Types.type_for(extension).first.content_type
    }

    RightAws::S3Generator.new(
        Settings.aws.key,
        Settings.aws.secret,
        :port => 80,
        :protocol => 'http').
      bucket(Settings.aws.bucket).
      get(s3_key, 2.hours, request_header, response_header)
  end
end

编辑:没有必要使用 RightAWS,uploader#url支持覆盖响应标头,语法有点混乱(就像 CarrierWave 的所有内容一样,恕我直言,但它仍然很棒):

Media.last.media.url(query: {"response-content-disposition" => "attachment; filename*=UTF-8''huhuhuhuhu"}) 

# results in: 
# => https://yourbucket.s3.amazonaws.com/media/512f292be75ab5a46f000001/yourfile.mp4?response-content-disposition=attachment%3B%20filename%2A%3DUTF-8%27%27huhuhuhuhu&AWSAccessKeyId=key&Signature=signature%3D&Expires=1362055338
于 2013-02-28T10:24:15.517 回答
0

如果您直接从 S3 将文件发送给用户,那么您别无选择。如果您通过测功机路由文件,您可以随意调用它,但在整个下载过程中您都在使用测功机。

我会尽可能以用户友好的方式存储文件,并使用文件夹来组织它们。

于 2011-10-12T15:39:13.577 回答