不幸的是,对于我的用例,没有办法使用标准 HTTP 标头或通过 Net::HTTP 请求获取预先计算的校验和。
解决方案:
如果您控制服务器,则可以添加任意标头,例如使用Nginx或Apache。
或者,可以创建并公开一个结构化字典文件,其中包含文件/校验和的键/值对,例如 JSON 中的以下(粗略)示例:
{ "md5-files": [
{"file1" : "60b725f10c9c85c70d97880dfe8191b3"},
{"file2" : "18ac6fe7ca693bb1767982e2eb3bbd0d")
]}
如果要在大量服务器上镜像同一个文件,则可能值得在本地构建这样一个结构化数组,并且只使用一个服务器来发出文件已远程更改的信号(例如 master-download-server-1 下载文件来自http://example.org/file1,将其与本地版本进行比较,然后更新文件。该文件可以由 slave-download-server1、slave-download-server2 解析以确定它们是否应该向示例发送请求。 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 文档不是很好,我完全希望亚马逊在某些时候会在没有警告的情况下更改它。根据我从亚马逊员工的各种论坛回复(!!)中拼凑出来的内容,标签的一般算法如下:
- 如果文件小于 5GB 并且被流式传输/非“多部分”上传到服务器,则 etag 可能是上传文件的 md5。
- 如果文件大于 5GB 或通过 'multipart' 上传,etag 似乎是上传文件的最后一块,用 md5-# 表示,其中 # 是文件的一部分(例如,上传文件的 3 块看起来像 18ac6fe7ca693bb1767982e2eb3bbd0d- 3 在标题中)。
不完美,但如果您的远程主机遵循可预测的模式,请检查标头并希望最好。