使用send_file从Amazon S3下载文件?

我在我的应用程序中有一个下载链接,用户应该能够下载存储在s3上的文件。 这些文件将公布在像这样的url上

https://s3.amazonaws.com/:bucket_name/:path/:to/:file.png 

下载链接命中我的控制器中的一个操作:

 class AttachmentsController < ApplicationController def show @attachment = Attachment.find(params[:id]) send_file(@attachment.file.url, disposition: 'attachment') end end 

但是当我尝试下载文件时出现以下错误:

 ActionController::MissingFile in AttachmentsController#show Cannot read file https://s3.amazonaws.com/:bucket_name/:path/:to/:file.png Rails.root: /Users/user/dev/rails/print Application Trace | Framework Trace | Full Trace app/controllers/attachments_controller.rb:9:in `show' 

该文件完全存在,可以在错误消息的url处公开访问。

我如何让用户下载S3文件?

为了从您的Web服务器发送文件,

  • 您需要从S3下载(请参阅@ nzajt的答案 )或

  • 你可以redirect_to @attachment.file.url

你也可以使用send_data

我喜欢这个选项,因为你有更好的控制。 您没有将用户发送给s3,这可能会让某些用户感到困惑。

我只是添加一个下载方法到AttachmentsController

 def download data = open("https://s3.amazonaws.com/PATTH TO YOUR FILE") send_data data.read, filename: "NAME YOU WANT.pdf", type: "application/pdf", disposition: 'inline', stream: 'true', buffer_size: '4096' end 

并添加路由

 get "attachments/download" 

保持简单的用户

我认为处理这个最好的方法是使用一个到期的S3url。 其他方法有以下问题:

  • 该文件首先下载到服务器,然后再下载到用户。
  • 使用send_data不会产生预期的“浏览器下载”。
  • 束缚Ruby进程。
  • 需要额外的download控制器操作。

我的实现如下所示:

在你的attachment.rb

 def download_url S3 = AWS::S3.new.buckets[ 'bucket_name' ] # This can be done elsewhere as well, # eg config/environments/development.rb url_options = { expires_in: 60.minutes, use_ssl: true, response_content_disposition: "attachment; filename=\"#{attachment_file_name}\"" } S3.objects[ self.path ].url_for( :read, url_options ).to_s end 

在你的意见

 <%= link_to 'Download Avicii by Avicii', attachment.download_url %> 

而已。


如果你仍然想保持你的download行动出于某种原因,那么只用这个:

在你的attachments_controller.rb

 def download redirect_to @attachment.download_url end 

感谢guilleva的指导。

以下是结束了我的工作。 从S3对象获取原始数据,然后使用send_data将其传递给浏览器。

使用这里find的aws-sdk gem文档http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/S3/S3Object.html

全控制器方法

 def download AWS.config({ access_key_id: "SECRET_KEY", secret_access_key: "SECRET_ACCESS_KEY" }) send_data( AWS::S3.new.buckets["S3_BUCKET"].objects["FILENAME"].read, { filename: "NAME_YOUR_FILE.pdf", type: "application/pdf", disposition: 'attachment', stream: 'true', buffer_size: '4096' } ) end 

我刚将我的public/system文件夹迁移到Amazon S3。 上面的解决scheme有助于我的应用程序接受不同种类 所以如果你需要相同的行为,这对我有帮助:

 @document = DriveDocument.where(id: params[:id]) if @document.present? @document.track_downloads(current_user) if current_user data = open(@document.attachment.expiring_url) send_data data.read, filename: @document.attachment_file_name, type: @document.attachment_content_type, disposition: 'attachment' end 

该文件正在保存在DriveDocument对象的attachment字段中。 我希望这有帮助。