Rails: 如何将文件从 S3 发送到远程服务器
Rails: How to send file from S3 to remote server
我一直在四处寻找,似乎找不到好的解决方案。我的 Rails 应用程序将其文件存储在 Amazon S3 中。我现在需要将它们发送到远程(第 3 方)服务。
我正在使用 RestClient post 到第 3 方服务器,如下所示:
send_file = RestClient::Request.execute(
:method => :post,
:url => "http://remote-server-url.com",
:payload => File.new("some_local_file.avi", 'rb'),
:multipart => true,
etc.... )
它适用于本地文件,但我如何才能将远程文件从 S3 直接发送到此第 3 方服务?
我在这里找到了有人使用 open-uri 的答案:ruby reading files from S3 with open-URI
我自己测试过,成功了。
:payload => open(URI.parse("http://amazon-s3-example.com/some_file.avi"))
但是,我在这里读到一条评论说 open-uri 只是将远程文件加载到内存中。请参阅对此答案的最后评论:
这不太理想,因为我要处理的视频文件可能很大。我还在某处读到 RestClient 甚至将本地文件加载到内存中;同样,这并不理想。有谁知道这是不是真的?
当然,我不可能是唯一遇到此问题的人。我知道我可以在发送之前在本地下载 S3 文件,但我希望节省时间和带宽。此外,如果 RestClient 确实 确实 甚至将本地文件加载到内存中,那么在本地下载它并不能为我节省任何东西。呵呵。
如有任何建议,我们将不胜感激。谢谢:)
更新:
远程服务器只是一个响应 post 请求的 API。我没有能力改变他们的任何事情。
看看:
https://github.com/rest-client/rest-client/blob/master/lib/restclient/payload.rb
RestClient 绝对支持流式上传。条件是在 payload 中你传递的东西不是字符串或散列,并且你传递的东西响应读取和大小。 (所以基本上是一个流)。
在 S3 端,您基本上需要抓取一个流,而不是在发送之前读取整个对象。你使用 http://docs.aws.amazon.com/sdkforruby/api/Aws/S3/Client.html#get_object-instance_method 并且你说你想在响应目标中获取一个 IO 对象(不是字符串)。为此,您可以使用 IO.pipe
reader, writer = IO.pipe
fork do
reader.close
s3.get_object(bucket: 'bucket-name', key: 'object-key') do |chunk|
writer.write(chunk)
end
end
writer.close
您将 reader 传递给 RestClient::Payload。生成并将其用作您的有效负载。如果阅读部分比写作部分慢,您可能仍会在内存中阅读很多内容。你想要的,在写入时只接受你愿意在内存中缓冲的数量。您可以使用 writer.stat.size(在分叉内)读取流的大小,并在它超过一定大小后旋转它。
我一直在四处寻找,似乎找不到好的解决方案。我的 Rails 应用程序将其文件存储在 Amazon S3 中。我现在需要将它们发送到远程(第 3 方)服务。
我正在使用 RestClient post 到第 3 方服务器,如下所示:
send_file = RestClient::Request.execute(
:method => :post,
:url => "http://remote-server-url.com",
:payload => File.new("some_local_file.avi", 'rb'),
:multipart => true,
etc.... )
它适用于本地文件,但我如何才能将远程文件从 S3 直接发送到此第 3 方服务?
我在这里找到了有人使用 open-uri 的答案:ruby reading files from S3 with open-URI
我自己测试过,成功了。
:payload => open(URI.parse("http://amazon-s3-example.com/some_file.avi"))
但是,我在这里读到一条评论说 open-uri 只是将远程文件加载到内存中。请参阅对此答案的最后评论:
这不太理想,因为我要处理的视频文件可能很大。我还在某处读到 RestClient 甚至将本地文件加载到内存中;同样,这并不理想。有谁知道这是不是真的?
当然,我不可能是唯一遇到此问题的人。我知道我可以在发送之前在本地下载 S3 文件,但我希望节省时间和带宽。此外,如果 RestClient 确实 确实 甚至将本地文件加载到内存中,那么在本地下载它并不能为我节省任何东西。呵呵。
如有任何建议,我们将不胜感激。谢谢:)
更新: 远程服务器只是一个响应 post 请求的 API。我没有能力改变他们的任何事情。
看看: https://github.com/rest-client/rest-client/blob/master/lib/restclient/payload.rb
RestClient 绝对支持流式上传。条件是在 payload 中你传递的东西不是字符串或散列,并且你传递的东西响应读取和大小。 (所以基本上是一个流)。
在 S3 端,您基本上需要抓取一个流,而不是在发送之前读取整个对象。你使用 http://docs.aws.amazon.com/sdkforruby/api/Aws/S3/Client.html#get_object-instance_method 并且你说你想在响应目标中获取一个 IO 对象(不是字符串)。为此,您可以使用 IO.pipe
reader, writer = IO.pipe
fork do
reader.close
s3.get_object(bucket: 'bucket-name', key: 'object-key') do |chunk|
writer.write(chunk)
end
end
writer.close
您将 reader 传递给 RestClient::Payload。生成并将其用作您的有效负载。如果阅读部分比写作部分慢,您可能仍会在内存中阅读很多内容。你想要的,在写入时只接受你愿意在内存中缓冲的数量。您可以使用 writer.stat.size(在分叉内)读取流的大小,并在它超过一定大小后旋转它。