2016-01-19 51 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网址已过期。