2

サーバー側でヘッダーを制御または追加することができずに、ファイル全体をダウンロードせずにローカル チェックサムをリモート ファイルと比較し、Ruby と Net::HTTP を使用してチェックサムを比較することは可能ですか?

Net::HTTP を使用して記述したクラスを使用してディスクにファイルを作成しています。リモート ファイルとローカル ファイルの SHA256 の合計を比較して、帯域幅の倹約を増やしたいと考えています。ローカル コピーがリモート バージョンと一致しない場合にのみ、リモート ファイルをダウンロードしたいと考えています。

ここに私の仮定があります:

  • ファイル名は同じかもしれませんが、内容が異なる場合があります。

  • HTTP ヘッダーの「最終変更」日付は、変更を示す適切な指標ではありません。cp /dir_a/file1.tar /dir_b/file2.tar結果として、チェックサムは同じになりますが、「最終変更」時刻が異なります。

  • HTTP ヘッダーの Etag は適切な指標ではありません。http: //example.org/file1.tarhttp://example.iana.org//file1.tarは、同じファイルに対して異なる Etag を持つ場合があります。

  • HTTP ヘッダーの Etag は完全に標準ではありません。EC2 は md5sums を使用して Etag を生成しますが、他のホストはそうではない場合があります。これにより、このタグ付け値のローカル生成が困難になります。

  • ホスト名から Etag への実装のハッシュ/辞書を維持することは扱いにくく、悪いアプローチです。

サーバー側のソフトウェアが、この目標を達成するためにファイル/タグ/チェックサムの比較を行うための機能を提供する必要があることは比較的確かですが (たとえば、ヘッダーまたは別のルックアップ ファイルのチェックサム フィールド)、この追求を放棄する前に、私の仮定を確認してください。実装にアプローチする方法を検討しているため、気が散らないように既存のコードを省略しました。

4

1 に答える 1

1

残念ながら、私のユース ケースでは、標準の HTTP ヘッダーまたは Net::HTTP 要求を使用して、事前に計算されたチェックサムを取得する方法はありません。

ソリューション:

サーバーを制御している場合は、NginxApacheなどを使用して任意のヘッダーを追加できます。

または、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 スタッフからのさまざまなフォーラムの応答(!!) から私がまとめたものから、タグの一般的なアルゴリズムは次のようになります。

  1. ファイルが 5GB 未満で、サーバーにストリーミング/非「マルチパート」アップロードされた場合、etag はアップロードされたファイルの md5 である可能性があります。
  2. ファイルが 5GB を超える場合、または「マルチパート」経由でアップロードされた場合、etag は md5-# で示されるアップロードされたファイルの最後のチャンクのように見えます。ここで # はファイルの一部です (たとえば、アップロードされたファイルの 3 つのチャンクは 18ac6fe7ca693bb1767982e2eb3bbd0d- のようになります)。ヘッダーの 3)。

完全ではありませんが、リモート ホストが予測可能なパターンに従っている場合は、ヘッダーを調べて最善を尽くしてください。

于 2013-04-30T15:32:46.390 に答える