以下是关于Azure的MD5验证和属性设置的工作原理。
在服务器端,Azure会计算每个上传文件的MD5值。
如果该上传文件恰好代表一个“完整文件”(完整的Blob——PutBlob是其内部名称),则它还将免费为您存储该MD5值在Blob属性中。它也会将其计算出来的值作为响应HTTP标头返回。
如果您在上传时传递了“Content-MD5”标头,则Azure(服务器)还将根据该值验证上传,并在不匹配时失败上传。同样,它会为您存储MD5值。
如果您不是在“一次性”上传中上传“完整文件”,则真正的奇怪之处就出现了。
如果您的文件大于
client.SingleBlobUploadThresholdInBytes(通常为32MB,C#
256MB),则 Azure 客户端
将会“将您的上传拆分成4MB块
[max用PutBlock上传每个块,然后使用PutBlockList方法提交所有块。”可能会并行上传块。Azure自身对任何单个上传都有100MB的硬限制,因此您无法将client.SingleBlobUploadThresholdInBytes调整到此其他限制之上(更新:可能已更改为
5GB)。您必须将上传拆分为每个块4MB的“块”(片段)。 (不相关的副作用是,在Azure中,“块”是可更改/可更新的,但不是单个字节。 “一次性”上传(最高限度为该限制)基本上包含一个大的“块”,因此基本上是不变的。 如果您进行多个块上传,则可以更改该blob中的单个块)。
如果您正在以“块”方式上传,Azure仅支持在上传时让服务器“验证”每个块的MD5值。因此,如果您将客户端参数设置为
setComputeMd5(true)
(Java)或
validate_content = true
(Python),它将在上传每个4MB块时计算其MD5,并将其传递以进行验证。文档说这在使用HTTPS时“不需要”,因为HTTPS还会对相同字节计算校验和并将其与传输一起包括,所以有些冗余。每个块的CONTENT-MD5被称为事务性(类似于短暂的)MD5。似乎一旦验证了该块,就会被丢弃。
这意味着,在使用“分块”上传的文件上传结束时,Azure 中不会设置 CONTENT-MD5 属性,因为它需要应用于“整个 blob”。Azure 不知道所有块按顺序组合在一起的 MD5 值应该是什么(它只处理随着数据传入而产生的每个传输的 MD5 值),并且在最后将所有块组合在一起时不会重新计算全局值。我们所知道的是,它实际上并没有将它们“组合”在一起,而只是在内部将块链接到彼此。这意味着,“有时候”当您使用相同的客户端调用进行上传时,它将设置 CONTENT-MD5 属性,有时候则不会(当文件被认为太大时)。
如果我们在上传时对整个文件进行了MD5处理,那么我们还有哪些选项呢?我们不能将其用作特定块的上传头。因此,Azure的PutBlockList命令被更改为接受“另一种”MD5形式,称为x-ms-blob-content-md5。如果使用这个选项,它基本上会设置Azure中blob的CONTENT-MD5属性,并且不会检查或验证它。实际上,如果在Azure中更新blob,则根本不会修改CONTENT-MD5属性,因此它可能过时。您也可以通过事后“设置blob属性”调用来在Azure中设置此属性,在上传后将其设置为任意值而不进行检查。C#客户端具有BlobOption以设置StoreBlobContentMD5,但似乎不允许您提供该值。Java客户端似乎没有此选项,因此在任何情况下都可以手动设置标头来提供它。如果您有任何支持"--put-md5"选项的客户端(例如azcopy),则该选项可能只是设置此属性,适用于大型文件。其他选项是在将字节传递给客户端时计算其MD5并检查是否匹配,并假设它们已经到达(InputStream包装样式)。或者在上传后重新计算文件的MD5(本地),并“希望”客户端读取并上传了与您刚刚读取的相同的字节(它会在每个块中计算事务性MD5和/或HTTPS校验和)。
或者痛苦的选项是:重新下载以验证其MD5是否有效。如果您想以这种方式进行操作,一种“简单”的方法是首先设置Azure CONTENT-MD5属性(参见上文),然后使用Azure客户端执行文件下载。在客户端上,它将在下载时计算md5,将其与azure中“当前设置”的md5进行比较(如果存在于azure中,则作为下载标头发送),如果最终不匹配,则客户端将失败该操作。因此,基本上,Azure支持在客户端验证大型文件的完整文件MD5,但不支持服务器端...或创建一个
Azure function 来执行类似于上传后的客户端验证等效操作。
还有一件类似MD5的事情是Azure支持的:如果您使用指定范围为4MB或更小的“获取blob”,还可以指定x-ms-range-get-content-md5
,它将在CONTENT-MD5 HTTP标头中返回该范围的MD5。顺便说一下。