簡體   English   中英

使用 send_file 從 Amazon S3 下載文件?

[英]Using send_file to download a file from 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 文件?

您也可以使用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"

為用戶保持簡單

我認為處理這個問題的最好方法是使用過期的 S3 url。 其他方法存在以下問題:

  • 文件先下載到服務器,然后再下載到用戶。
  • 使用send_data不會產生預期的“瀏覽器下載”。
  • 捆綁 Ruby 進程。
  • 需要額外的download控制器操作。

我的實現是這樣的:

在你的attachment.rb

def download_url
  S3 = AWS::S3.new.buckets[ 'bucket_name' ] # This can be done elsewhere as well,
                                            # e.g 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 下載它(請參閱@nzajt 的回答)或

  • 你可以redirect_to @attachment.file.expiring_url(10)

我剛剛將我的public/system文件夾遷移到 Amazon S3。 上述解決方案有幫助,但我的應用程序接受不同類型的文檔。 因此,如果您需要相同的行為,這對我有幫助:

@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字段中。 我希望這有幫助。

以下是最終對我有用的內容。 從 S3 對象獲取原始數據,然后使用send_data將其傳遞給瀏覽器。

使用此處找到的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

如何允許用戶下載 S3 文件?

如果您能夠在將文件上傳到 S3 之前在文件上設置一些元數據,而不是在用戶以后想要下載它時嘗試修補它,那么這個解決方案就簡單得多:

https://stackoverflow.com/a/24297799/763231

如果您使用fog那么您可以執行以下操作:

 has_attached_file :report, fog_file: lambda { |attachment| { content_type: 'text/csv', content_disposition: "attachment; filename=#{attachment.original_filename}", } }

如果您使用 Amazon S3 作為您的存儲提供商,那么應該可以使用以下方法:

 has_attached_file :report s3_headers: lambda { |attachment| { 'Content-Type' => 'text/csv', 'Content-Disposition' => "attachment; filename=#{attachment.original_filename}", } }

def download_pdf @post= @post.avatar.service_url

send_data(

    "#{Rails.root}/public/#{@post}",
    filename: "#{@post}",
    type: "image/*",
    disposition: 'inline', stream: 'true', buffer_size: '4096'
)

結尾

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM