Development Tip

send_file을 사용하여 Amazon S3에서 파일을 다운로드합니까?

yourdevel 2021. 1. 5. 19:43
반응형

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 파일을 다운로드하도록 허용하려면 어떻게해야합니까?


웹 서버에서 파일을 보내려면

  • S3에서 다운로드해야합니다 ( @nzajt의 답변 참조 ) 또는

  • 당신은 할 수 있습니다 redirect_to @attachment.file.expiring_url(10)


당신은 또한 사용할 수 있습니다 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 에게 감사드립니다 .


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

The file is being saved in the attachment field of DriveDocument object. I hope this helps.


The following is what ended up working well for me. Getting the raw data from the S3 object and then using send_data to pass that on to the browser.

Using the aws-sdk gem documentation found here http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/S3/S3Object.html

full controller method

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

ReferenceURL : https://stackoverflow.com/questions/12277971/using-send-file-to-download-a-file-from-amazon-s3

반응형