Ruby net/http PUT リクエストでのストリーミング データ

概要

Ruby-doc Net/HTTP には、ストリーミング応答本文の詳細な例が記載されています。これは、大きなファイルをダウンロードしようとするときに適用されます。

PUT 経由でファイルをアップロードするための同等のコード スニペットを探しています。コードを機能させるためにかなりの時間を費やしましたが、うまくいきませんでした。特定のインターフェイスを実装し、それを request.body_stream に渡す必要があると思います

ストリーミングが必要なのは、ファイルのアップロード中にファイルの内容を変更するため、アップロード中にバッファリングされたチャンクにアクセスできるようにしたいためです。ストリーミングを使用できる限り、http.rb やrest-client などのライブラリを喜んで使用します。

前もって感謝します! 参考までに、動作する非ストリーミングバージョンを以下に示します。


    uri = URI("http://localhost:1234/upload")

    Net::HTTP.start(uri.host, uri.port) do |http|
      request = Net::HTTP::Put.new uri

      File.open("/home/files/somefile") do |f|
        request.body = f.read()
      end

      # Ideally I would need to use **request.body_stream** instead of **body** to get streaming

      http.request request do |response|
        response.read_body do |result|
          # display the operation result   
          puts result
        end
      end
    end

解決策

#body_stream= は「IO のような」オブジェクトを期待します。ありがたいことに、ファイルはすでに 1 つです。以下は、ファイルをチャンクでストリーミングするように例を適応させています。これは、使用可能なメモリに収まらない大きなファイルでも機能します。 #request を呼び出すときは、ファイルがまだ開いている必要があることに注意してください。

require 'net/http'

uri = URI("http://localhost:1234/upload")

response = Net::HTTP.start(uri.host, uri.port) do |http|
  request = Net::HTTP::Put.new uri
  File.open('/home/files/somefile') do |file|
    request['Content-Length'] = file.size
    request.body_stream = file
    http.request(request)
  end
end

puts response.body

サーバーは解析をどこで停止するかを認識する必要があるため、プロトコルにはアップフロント長またはチャンク転送エンコーディングのいずれかが必要です。事前に長さがわからない場合は、Content-Length を次のものに置き換えます。 Net::HTTP はチャンク化を自動的に処理します。

request['Transfer-Encoding'] = 'chunked'

ファイル以外をストリーミングする場合は、#body_stream= オブジェクトに IO#read を実装します。