Ruby on rails 使用Send_文件到远程源(Ruby on Rails)

Ruby on rails 使用Send_文件到远程源(Ruby on Rails),ruby-on-rails,Ruby On Rails,在我的应用程序中,我有一个困扰我的需求 我有一个存储在S3中的文件,当用户单击我应用程序中的链接时,我会登录他们单击链接的数据库,将他们的“下载信用”额度减少1,然后我想提示下载该文件 我不想简单地将用户重定向到该文件,因为它存储在S3中,我不想让他们拥有源文件的链接(这样我就可以保持完整性和访问) 看起来send_file()无法与远程源文件一起使用,有人推荐gem或合适的代码来实现这一点吗?从S3 bucket/对象读取文件时,您需要将文件内容流式传输给用户 如果您使用该库,类似的操作可能会

在我的应用程序中,我有一个困扰我的需求

我有一个存储在S3中的文件,当用户单击我应用程序中的链接时,我会登录他们单击链接的数据库,将他们的“下载信用”额度减少1,然后我想提示下载该文件

我不想简单地将用户重定向到该文件,因为它存储在S3中,我不想让他们拥有源文件的链接(这样我就可以保持完整性和访问)


看起来send_file()无法与远程源文件一起使用,有人推荐gem或合适的代码来实现这一点吗?

从S3 bucket/对象读取文件时,您需要将文件内容流式传输给用户

如果您使用该库,类似的操作可能会起作用:

 send_file_headers!( :length=>S3Object.about(<s3 object>, <s3 bucket>)["content-length"], :filename=><the filename> )
 render :status => 200, :text => Proc.new { |response, output|
   S3Object.stream(<s3 object>, <s3 bucket>) do |chunk|
     output.write chunk
   end
 }
发送文件头!(:length=>S3Object.about(,)[“content length”],:filename=>)
render:status=>200,:text=>Proc.new{|响应,输出|
S3Object.stream(,)do | chunk|
output.write块
结束
}
此代码主要复制自send_文件代码,该代码本身仅适用于本地文件或类似文件的对象

注意:无论如何,我建议不要从rails进程本身提供文件。如果您的用例可能/可接受,我将使用经过身份验证的GET来服务bucket中的私有数据

使用经过身份验证的GET,您可以保持bucket及其对象的私有性,同时通过创建包含身份验证签名令牌的URL,允许临时权限读取特定对象内容。用户只需重定向到经过身份验证的URL,令牌就可以在几分钟内有效

使用上述AWS::S3,您可以通过以下方式获得经过身份验证的GET url:

 time_of_exipry = Time.now + 2.minutes
 S3Object.url_for(<s3 object>, <s3 bucket>,
                  :expires => time_of_exipry)
time\u of\u exipry=time.now+2.5分钟
S3Object.url\u用于(,
:expires=>timeofexipry)

您可以从S3读取文件并将其本地写入非公共目录,然后使用X-Sendfile(apache)或X-Accel-Redirect(nginx)提供内容

对于nginx,您可以在配置中包括以下内容:


            location /private {
                                 internal;
                                 alias /path/to/private/directory/;
            }
然后在rails控制器中执行以下操作:


   response.headers['Content-Type'] = your_content_type
   response.headers['Content-Disposition'] = "attachment; filename=#{your_file_name}"
   response.headers['Cache-Control'] =  "private"
   response.headers['X-Accel-Redirect'] = path_to_your_file
   render :nothing=>true

这个过程的一个好方法是使用临时文件(tested rails 3.2)的完整图像下载方法:


您所说的是正确的,但是如果文件不是web服务器的本地文件,有没有办法做到这一点?目前的问题是,这些文件存储在S3 web服务上。我认为,除非每个用户都有自己的S3帐户,否则您不能授予他们对S3文件的直接访问权限。您必须将文件从S3下载到本地服务器并从那里发送。S3文件通常是公共的,只是使用模糊的URI。似乎您尝试实现的效果可以在不复制文件的情况下实现,请参阅此处的讨论:。不过,您必须完成两个阶段:登录,然后发送文件请求。我刚刚在s3 api中验证了Luca的方法,未经测试,但看起来是正确的-+1S3ojBect.url_看起来是最好的方法。我们使用了一年的重定向,但现在我们真的希望Safari/Mac能够工作:发送文件头!是私有的,send_数据或send_文件都不接受远程文件;变通方法,但仅供参考。我认为您生成过期时间的方法实际上不起作用,您需要执行:
time\u of\u expiry=2.minutes.from\u now.to\u i
或者您可以执行
:expires\u in=>60*2
或者您可以避免
:expires\u in
键,并让它在5分钟内过期,这是默认值。可能复制的作品像一个魅力!临时文件在GC上自动删除!
def download
  @image = Image.find(params[:image_id])

  open(@image.url) {|img|
    tmpfile = Tempfile.new("download.jpg")
    File.open(tmpfile.path, 'wb') do |f| 
      f.write img.read
    end 
    send_file tmpfile.path, :filename => "great-image.jpg"
  }   
end