python 使用 put_block_blob_from_path 上传 blob 时 azure blob 存储 md5 检查失败

python azure blob storage md5 check fails on blob upload using put_block_blob_from_path

我正在尝试使用 python sdk 将 blob 上传到 azure blob 存储。我想在上传后在服务器端传递MD5哈希进行验证。

代码如下:

blob_service.put_block_blob_from_path(
        container_name='container_name',
        blob_name='upload_dir/'+object_name,
        file_path=object_name,
        content_md5=object_md5Hash
)

但是我得到这个错误:

AzureHttpError: The MD5 value specified in the request did not match with the MD5 value calculated by the server.

文件约为 200mb,错误立即抛出。不上传文件。所以我怀疑它可能正在将提供的哈希值与第一个块的哈希值或其他东西进行比较。

有什么想法吗?

我查看了 Azure Blob Storage SDK 函数 put_block_blob_from_path 的源代码。函数注释中解释了大小写,请看下面内容,参考https://github.com/Azure/azure-storage-python/blob/master/azure/storage/blob/blobservice.py.

content_md5:

Optional. An MD5 hash of the blob content. This hash is used to verify the integrity of the blob during transport. When this header is specified, the storage service checks the hash that has arrived with the one that was sent. If the two hashes do not match, the operation will fail with error code 400 (Bad Request).

我认为这里发生了两件事。

  • SDK 中的错误 - 我相信您已经发现了 SDK 中的错误。我在 Github 上查看了此函数的源代码,发现当以块的形式上传大 blob 时,SDK 首先尝试创建一个空块 blob。对于块 blob,这不是必需的。当它创建空块 blob 时,它不会发送任何数据。但是您正在设置 content-md5,SDK 会将您发送的 content-md5 与空内容的 content-md5 进行比较,因为它们不匹配,所以您会收到错误。

要临时解决此问题,请修改 blobservice.py 中的源代码并注释掉以下代码行:

    self.put_blob(
        container_name,
        blob_name,
        None,
        'BlockBlob',
        content_encoding,
        content_language,
        content_md5,
        cache_control,
        x_ms_blob_content_type,
        x_ms_blob_content_encoding,
        x_ms_blob_content_language,
        x_ms_blob_content_md5,
        x_ms_blob_cache_control,
        x_ms_meta_name_values,
        x_ms_lease_id,
    )

我为此在 Github 上创建了一个新问题:https://github.com/Azure/azure-storage-python/issues/99

  • 用法不正确 - 我注意到您在 content_md5 参数中传递了文件的 md5 散列。这对你不起作用。您实际上应该在 x_ms_blob_content_md5 参数中传递 md5 哈希。所以你的电话应该是:
blob_service.put_block_blob_from_path(
        container_name='container_name',
        blob_name='upload_dir/'+object_name,
        file_path=object_name,
        x_ms_blob_content_md5=object_md5Hash
)

这是一种 SDK 错误,我们应该抛出更好的错误消息而不是点击服务,但验证必须分块的大型上传内容根本行不通。 x_ms_blob_content_md5 将存储 md5 但服务不会验证它。这是你可以在下载时做的事情。 content_md5 由服务器针对特定请求的主体进行验证,但由于有不止一个具有块状 blob,因此它永远无法工作。

因此,如果 blob 足够小(小于 BLOB_MAX_DATA_SIZE)可以放在单个请求中,content_md5 就可以正常工作。否则,如果您认为您可能想要使用 HTTP 下载并在下载时验证它,我只是建议使用 HTTPS 并将 MD5 存储在 x_ms_blob_content_md5 中。 HTTPS 已经为网络上的位翻转等提供了验证,因此将它用于 upload/download 会做很多事情。如果您出于某种原因无法 upload/download 使用 HTTPS,您可以考虑使用 put 块和 put 块列表 API 自行对 blob 进行分块。

仅供参考:在未来的版本中,我们确实打算在库本身中为单次放置和分块操作添加自动 MD5 计算,这将完全解决这个问题。对于下一个版本,如果为分块下载指定 content_md5,我们将添加改进的错误消息。