使用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
字段中。 我希望这有帮助。