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(在分叉内)读取流的大小,并在它超过一定大小后旋转它。