是否可以在用户右键单击之前重命名文件名?另存为 Carrierwave + S3 + Heroku +内容处置?

发布于 2024-12-08 21:07:12 字数 560 浏览 1 评论 0原文

是否可以在用户右键单击 + 另存为之前使用 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 不会提供此服务,因为它首先将文件缓存在本地文件系统中,然后将其发送到浏览器。它占用了整个 Web 进程(Heroku 中的 Dyno)。

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

Is it possible to rename a file name before user right-click's + save as with Carrierwave + S3 + Heroku + Content-Disposition? I'm thinking of sanitizing file names (e.g. 193712391231.flv) before the file is saved on the S3 server and saving the original file name in a column in the db.

When a user decides to download the file (right-click and save as). I can't serve / send it as 193712391231.flv. Instead, I would like to send the file with its original file name.

How can this be implemented?

Using Carrierwave. I've come across this:

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

send_file uploader.file.path

This wont be served by S3, because it first caches the file in the local filesystem and then sends it to the browser. Which takes up a whole web process (Dyno in Heroku).

If anyone has any ideas, please suggest.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

忆依然 2024-12-15 21:07:12

Akshully,您可以:

# 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

model.media.url 生成的 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

Akshully, you can:

# 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

The url that model.media.url yields will then return the following headers:

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
...

The browser will then force a download (instead of opening in browser) and use the filename you set, regardless of the file name use used to store stuff in the bucket. The only drawback of this is that the Content-Disposition header is set when Carrierwave creates the file, so you couldn't for example use different filenames on the same file for different users.

In that case you could use RightAWS to generate the signed 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

EDIT: It is not necessary to use RightAWS, uploader#url supports overriding response headers, the syntax is just a bit confusing (as is everything with CarrierWave, imho, but it's still awesome):

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
月下客 2024-12-15 21:07:12

如果您直接从 S3 将文件发送给用户,则别无选择。如果您通过测功机路由文件,您可以将其命名为您想要的名称,但您在整个下载过程中都在使用测功机。

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

If you're sending the file to the user direct from S3 you've no option. If you route the file through a dyno you can call it what you want, but you're using a dyno for the entire duration of the download.

I would store the files in a user friendly manner where possible and use folders to organise them.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文