2009-08-24 4 views
11

내 앱에서 저를 괴롭히는 요구 사항이 있습니다.Send_File을 원격 소스에 사용하기 (Ruby on Rails)

나는 S3에 저장된 파일을 가지고 있는데, 사용자가 내 앱의 링크를 클릭하면 링크를 클릭 한 DB에 로그인하여 '다운로드 크레딧'한도를 줄인 후 다운로드를 위해 파일을 프롬프트합니다.

는 단순히 그것이 S3에 저장되어 있기 때문에 파일로 사용자를 리디렉션하고 싶지 않아 나는

(I 무결성 및 액세스를 유지할 수 있도록)들이 소스 파일의 링크를 싶지 않아

send_file()이 원격 소스 파일에서 작동하지 않는 것처럼 보입니다. 누구나이 작업을 수행 할 수있는 보석 또는 적합한 코드를 권장합니까?

+0

가능한 복제본 [브라우저에서 파일을 다운로드하려면 \ _ 데이터를 보내려면 어떻게합니까?] (http://stackoverflow.com/questions/7337508/how-to-force-send-data-to-download- the-file-in-the-browser) –

답변

9

S3 버켓/개체에서 파일을 읽는 동안 사용자에게 파일 내용을 스트리밍해야합니다.

이 같은 AWS::S3 라이브러리 무언가가 작동하지 않을 수 있습니다 사용하는 경우 :이 코드는 대부분 양식을 로컬 파일 또는 파일 - 류의 객체

N.B. 작동 자체로 send_file 코드를 복사

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 
} 

필자는 필연적으로 레일 프로세스 자체에서 파일을 제공하는 것에 대해 조언 할 것입니다. 가능하다면 허용되는 경우 GET 인증을 사용하여 버킷의 개인 데이터를 제공합니다.

인증 된 GET을 사용하면 버킷과 그 개체를 비공개로 유지하면서 인증 서명 토큰이 포함 된 URL을 만들어 특정 개체 콘텐츠를 읽을 수있는 임시 권한을 허용 할 수 있습니다. 사용자는 단순히 인증 된 URL로 리디렉션되며 토큰은 몇 분 동안 유효하게 만들 수 있습니다. 사용 후, 당신은 비공개 디렉토리에 로컬 S3에서 파일을 읽고 쓸 수

time_of_exipry = Time.now + 2.minutes 
S3Object.url_for(<s3 object>, <s3 bucket>, 
        :expires => time_of_exipry) 
+0

S3Ojbect.url_for는 최상의 접근 방식처럼 보입니다 – klochner

+2

우리는 1 년 동안 리디렉션을 사용했습니다. 그러나 이제는 Safari/Mac이 실제로 작동하기를 바랍니다. http://stackoverflow.com/questions/1995589/html5-audio-safari-live-broadcast-vs-not send_file_headers!send_data 또는 send_file 둘 다 원격 파일을 허용하지 않습니다. workaroundable하지만 다만 FYI – kain

+0

나는 time_of_expiry를 생성하는 방법이 실제로 작동하지 않을 것이라고 생각한다 :'time_of_expiry = 2.minutes.from_now.to_i' – Raphael

3

:

:: S3이 방법으로 인증 된 GET URL을 얻을 수 있습니다 위에서 언급 한 AWS를 사용하여 콘텐츠를 제공하는 X-Sendfile (apache) 또는 X-Accel-Redirect (nginx).

이 nginx를 들어 당신은 당신의 설정에 다음과 같은 것을 포함 할 것이다 :


    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 

과정의 좋은 작성자가 here입니다 : 당신의 레일 컨트롤러에서 다음


      location /private { 
           internal; 
           alias /path/to/private/directory/; 
      } 

을, 다음을 수행

+0

당신이 말한 것은 정확하지만 지역에있는 파일없이 그렇게 할 수있는 방법이 있습니다. 웹 서버? 현재의 문제는 파일이 S3 웹 서비스에 저장된다는 것입니다. – LucaM

+1

S3 사용자가 자신의 S3 계정을 갖고 있지 않으면 사용자 당 사용자에게 직접 액세스 할 수있는 권한을 부여 할 수 없다고 생각합니다. S3에서 로컬 서버로 파일을 다운로드하고 거기에서 보내야합니다. – klochner

+0

s3 파일은 흔히 난독 화 된 URI를 사용하여 공개됩니다. 파일을 복사하지 않고도 달성하려는 효과가있는 것처럼 보일 수 있습니다. 여기의 토론을 참조하십시오 : http://www.ruby-forum.com/topic/132214. 두 단계를 수행해야하지만, 로그인 한 다음 파일 요청을 보냅니다. – austinfromboston

3

임시 파일 (테스트 된 레일 3.2)을 사용한 전체 이미지 다운로드 방법 :

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 
+0

매력처럼 작동합니다! 임시 파일은 GC에서 자동으로 삭제됩니다! –