我需要能够通过Rails应用程序从S3存储桶中下载大文件。我通常只会向用户提供3S存储桶的URL,但我需要它保持屏蔽状态,以便我可以随意过期或删除URL。我做了类似以下的事情:
def download
purchase = Purchase.find(params[:id])
data = open(purchase[:download_url])
send_data data.read, filename: purchase[:file_name]
end
它适用于较小的文件,但是在1GB上,比如1GB,由于Heroku的超时限制,用户会收到大量的520错误。
我理解这里发生了什么:整个文件在被发送给用户之前在我的应用程序中打开,这就是为什么大文件超时的原因。我想知道的是,如果没有给用户S3 URL,是否有办法解决这个问题?是否可以,而不是下载文件,只是掩盖URL(而不是重定向)?
感谢任何帮助!
修改
根据SO的其他答案,我尝试实施过期网址:
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
,但我可能错误地构建了URL。再次,任何帮助表示赞赏!
答案 0 :(得分:2)
我认为您的S3对象网址无法访问,因为存储桶/对象没有public-read
。
要允许人们直接从S3存储桶下载,您可以:
使S3存储桶可公开访问
如果您使用此方法,则可以像更新的问题一样提供S3对象网址。您只需在AWS中配置存储桶。
复制并粘贴以下存储桶策略:
{
"Version":"2012-10-17",
"Statement":[
{
"Sid":"AddPerm",
"Effect":"Allow",
"Principal": "*",
"Action":["s3:GetObject"],
"Resource":["arn:aws:s3:::examplebucket/*"]
}
]
}
点击保存。现在,任何用户都可以下载此存储桶中的任何对象,只要他们有URL即可。作为提示,要禁止猜测URL,您可以使用合理长度的随机字符串重命名对象密钥。
创建预先签名的网址
在此方法中,只有拥有预分配网址的用户才能在特定时间段内下载您的S3对象(默认情况下,它为一周)。在那之后,他/她需要一个新的。要创建预签名的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。
答案 1 :(得分:0)
您不需要发送数据,只需设置代理网址,重定向到S3网址,或者您需要以编程方式执行的任何其他操作。
另请注意,S3网址已过期。