2016-01-19 80 views
0

我需要能夠從S3存儲桶中以Rails應用程序的形式下載大文件。我通常只是給用戶提供3S桶的URL,但我需要它保持屏蔽,以便我可以隨意過期或刪除URL。我在做類似如下:從S3在Rails上提供大文件

def download 
    purchase = Purchase.find(params[:id]) 

    data = open(purchase[:download_url]) 
    send_data data.read, filename: purchase[:file_name] 
end 

它適用於較小的文件,但是,一個就是,說1GB,因爲Heroku的超時限制,用戶得到一個大胖子的520錯誤。

我知道這裏發生了什麼:在發送給用戶之前,整個文件正在我的應用程序中打開,這就是爲什麼大文件超時的原因。我想知道的是,如果有一種解決方法,而不給用戶S3 URL?是否可以,而不是下載文件,只是掩蓋網址(不重定向)?

任何幫助表示讚賞!

編輯

基於上的其他答案,我試圖執行一個到期網址:

def download 
    purchase = Purchase.find(params[:id]) 
    path = purchase[:download_url].sub! 'entire URL until bucket path', '' 
    s3URL = AWS::S3::S3Object.new(S3_BUCKET, path) 

    redirect_to s3URL.url_for(:read).to_s 
end 

這只是重定向到AWS的AccessDenied,但也許我建立的網址不正確。再次,任何幫助表示讚賞!

回答

2

我認爲你的S3對象url是無法訪問的,因爲桶/對象沒有public-read

爲了讓人們直接下載從你的S3存儲,您可以:

  • 讓你的水桶公衆開放,或
  • 創建presigned URL授權匿名用戶S3下載該文件。

製作S3桶公衆開放

如果按照這個方法,你可以給S3對象的網址爲您更新的問題。您只需在AWS中配置存儲桶。

  1. 轉到S3控制檯。
  2. 打開您的存儲桶屬性(右鍵單擊您的存儲桶並單擊屬性)。
  3. 點擊權限部分,然後點擊添加存儲桶策略
  4. 複製並粘貼以下桶政策:

    { 
        "Version":"2012-10-17", 
        "Statement":[ 
        { 
         "Sid":"AddPerm", 
         "Effect":"Allow", 
         "Principal": "*", 
         "Action":["s3:GetObject"], 
         "Resource":["arn:aws:s3:::examplebucket/*"] 
        } 
        ] 
    } 
    

    來源:http://docs.aws.amazon.com/AmazonS3/latest/dev/example-bucket-policies.html#example-bucket-policies-use-case-2

  5. 點擊保存。現在,只要具有該URL,任何用戶都可以下載該存儲桶中的任何對象。作爲提示,爲了不允許猜測URL,您可以使用合理長度的隨機字符串重命名對象鍵。

創建presigned網址

在這種方法中,只有用戶誰擁有presigned網址可以下載在一段時間內您的S3對象(默認情況下,它是一個星期)。之後,他/她需要得到一個新的。要創建presigned S3對象:

def download 
    purchase = Purchase.find(params[:id]) 
    path = purchase[:download_url].sub! 'entire URL until bucket path', '' 

    s3 = Aws::S3::Resource.new(region:'us-west-2') 
    object = s3.bucket(S3_BUCKET).object(path) 
    redirect_to object.presigned_url(:get) 
end 

您也可以設置在object.presigned_url方法像一些選項:

object.presigned_url(:get, expires_in: 3600, response_content_disposition: 'attachment; filename=original_file_name.zip') 

詳情請閱讀http://docs.aws.amazon.com/sdkforruby/api/Aws/S3/Object.html#presigned_url-instance_method

您需要選擇哪一個適合您的情況。對於非敏感和公開的S3對象,我更願意讓公共S3可訪問。但是,我認爲,對於您的情況(購買並下載),最好是實施預先設置的URL。

+0

嘿,愛德華謝謝你!我正在選擇你的第二個解決方案,除非我使用'url_for'因爲我使用了gem的v1。它產生類似於https://mybucket.s3.amazonaws.com/bucket_path_file.zip?AWSAccessKeyId = XXXXX&Expires = 1453753227&Signature = XXXXX&response-content-disposition = attachment' - 我現在的問題是'https://mybucket.s3 .amazonaws.com/bucket_path_file.zip'仍然有效。我應該如何處理我的政策/權限以防止出現這種情況? –

+0

是的,生成的url看起來像一個預先註冊的url。你是如何上傳你的物品的?您是否將ACL設置爲「public-read」? –

+0

是的,它是'公開閱讀'。我在我的Rails控制器中創建對象數據,如下所示:'S3_BUCKET.presigned_post(key:「#{SecureRandom.uuid} - $ {filename}」,success_action_status:'201',acl:'public-read')'和然後將這個信息傳遞給[jQuery-File-Upload](https://github.com/blueimp/jQuery-File-Upload)來處理其餘部分。 ACL應該設置爲什麼? –

0

您不需要發送數據,只需設置代理網址,重定向到S3網址,或者任何您需要編程的地方。

同時請注意,S3網址已過期。