残念ながら、私のユース ケースでは、標準の HTTP ヘッダーまたは Net::HTTP 要求を使用して、事前に計算されたチェックサムを取得する方法はありません。
ソリューション:
サーバーを制御している場合は、NginxやApacheなどを使用して任意のヘッダーを追加できます。
または、JSON での次の (おおざっぱな) 例のように、ファイル/チェックサムのキー/値のペアを含む構造化された辞書ファイルを作成して公開することもできます。
{ "md5-files": [
{"file1" : "60b725f10c9c85c70d97880dfe8191b3"},
{"file2" : "18ac6fe7ca693bb1767982e2eb3bbd0d")
]}
多数のサーバーで同じファイルをミラーリングする場合は、そのような構造化された配列をローカルで構築し、1 つのサーバーのみを使用してファイルがリモートで変更されたことを通知することをお勧めします(例: master-download-server-1 はファイルをダウンロードします)。http://example.org/file1から、それをローカル バージョンと比較し、ファイルを更新します. このファイルは、slave-download-server1、slave-download-server2 によって解析され、リクエストを example に送信する必要があるかどうかを判断できます. org (または master-download-server-1 自体)。
最後に、私は Amazon の S3 から頻繁にダウンロードするので、クライアントのみのサービスとして機能しているときに使用できる唯一のオプションを使用しました。つまり、ヘッダーで返されるetagに依存することです。残念ながら、これに関するドキュメントは素晴らしいものではありませんが、私のアプローチの大まかなスニペットを 次に示します。
...
#I actually call my own encryption-helper, filename-parsing methods,
#but meta-code for the sake of example:
def example_file_getter(uri, docroot, file)
checksum = Digest::MD5.hexdigest(File.read(file))
uri = URI.parse(uri)
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Get.new(uri.request_uri)
response = http.request(request)
if response['etag'] != nil
etag = response['etag'].gsub!(/\"/,'')
end
if etag == checksum
file_existed = true
end
if ! File::exists?(destination) && ! file_existed
...actually fetch the file
...
[再び、メタコード; これは、私の元の質問に関連する重要な部分の要約です]
繰り返しますが、etag のドキュメントは良くありません。Amazon は、ある時点で警告なしにこれを変更することを完全に期待しています。Amazon スタッフからのさまざまなフォーラムの応答(!!) から私がまとめたものから、タグの一般的なアルゴリズムは次のようになります。
- ファイルが 5GB 未満で、サーバーにストリーミング/非「マルチパート」アップロードされた場合、etag はアップロードされたファイルの md5 である可能性があります。
- ファイルが 5GB を超える場合、または「マルチパート」経由でアップロードされた場合、etag は md5-# で示されるアップロードされたファイルの最後のチャンクのように見えます。ここで # はファイルの一部です (たとえば、アップロードされたファイルの 3 つのチャンクは 18ac6fe7ca693bb1767982e2eb3bbd0d- のようになります)。ヘッダーの 3)。
完全ではありませんが、リモート ホストが予測可能なパターンに従っている場合は、ヘッダーを調べて最善を尽くしてください。