【问题标题】:How to resolve an InvalidMd5 error returned from the Windows Azure Blob Storage service?如何解决从 Windows Azure Blob 存储服务返回的 InvalidMd5 错误?
【发布时间】:2011-05-04 14:30:55
【问题描述】:

我正在构建一个应用程序,该应用程序需要允许用户将大图像(最大约 100 MB)上传到 Windows Azure Blob 存储服务。在阅读了 Rob Gillen's excellent article 关于 Windows Azure 文件上传优化的内容后,我借用了他的方法来并行上传文件块,在 Parallel.For 循环中使用 CloudBlockBlob.PutBlock() 方法(代码可用 here)。

我遇到的问题是,每当我尝试上传文件时,我都会从 storage client 收到“InvalidMd5”异常。怀疑问题可能出在开发存储中,我还尝试对我的实时 Azure 存储帐户运行代码,但我得到了同样的错误。查看Fiddler 的流量,我看到“Content-MD5”标头设置为有效的 MD5 哈希。错误描述说“请求中指定的 MD5 值无效。MD5 值必须是 128 位和 Base64 编码的。”,但据我所知,我看到的值在 Fiddler 中发送是有效的(例如 a91c588092cedbdb1b82c2d3786fd509)。

这是我用于计算哈希的代码(由 Rob Gillen 提供):

public static string GetMD5HashFromStream(byte[] data)
{
    MD5 md5 = new MD5CryptoServiceProvider();
    byte[] retVal = md5.ComputeHash(data);

    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < retVal.Length; i++)
    {
        sb.Append(retVal[i].ToString("x2"));
    }
    return sb.ToString();
}

这是对 PutBlock() 的实际调用:

blob.PutBlock(transferDetails[j].BlockId, new MemoryStream(buff), blockHash, options);

我也尝试像这样传递哈希:

Convert.ToBase64String(Encoding.UTF8.GetBytes(blockHash))

但结果是一样的——“InvalidMd5”错误:(

使用 base64 编码(例如 YTkxYzU4ODA5MmNlZGJkYjFiODJjMmQzNzg2ZmQ1MDk=)传递给 PutBlock() 的 MD5 哈希值(例如 a91c588092cedbdb1b82c2d3786fd509)似乎没有什么区别。

Rob 的code 显然对他有用,我真的不知道是什么导致了我的问题。我对 Rob 的代码所做的唯一更改是更改 ParallelUpload() 扩展方法以采用 Stream 而不是文件名,并根据上传文件的大小动态确定块大小。

如果有人知道如何解决这个问题,请告诉我!我将不胜感激!我已经为此苦苦挣扎了两天。

【问题讨论】:

    标签: azure azure-blob-storage


    【解决方案1】:

    Rob,感谢您提供帮助并指出 MD5 哈希值的差异。你的回答让我想到了正确的方向。我又花了一整天的时间研究这个,但幸运的是(感谢你的评论:))我终于设法解决了这个问题。事实证明,我的情况实际上有两个问题:

    1) MD5 散列:我注意到您粘贴在答案中的散列比我得到的要短,但我花了一段时间才发现您的散列正好是 两倍强>短。经过一些实验,我发现您的测试应用程序中的 GetMD5HashFromStream() 方法正在将 MD5CryptoServiceProvider 生成的 16 字节 哈希转换为32 个字符 字符串。正是这个 32 个字符的字符串导致了问题,因为它被转换为 Base64 并传递给 PutBlock() 方法,因此长度增加了一倍,因此哈希无效Blob 存储服务抱怨的问题。这是我最终得到的代码:

    原文:

    public static string GetMD5HashFromStream(byte[] data)
    {
        MD5 md5 = new MD5CryptoServiceProvider();
        byte[] retVal = md5.ComputeHash(data);
    
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < retVal.Length; i++)
        {
            sb.Append(retVal[i].ToString("x2"));
        }
        return sb.ToString();
    }
    

    以及对 PutBlock() 的调用:

    // calculate the block-level hash
    string blockHash = Helpers.GetMD5HashFromStream(buff);
    blob.PutBlock(transferDetails[j].BlockId, new MemoryStream(buff), blockHash, options);
    

    决赛:

    MD5 md5 = new MD5CryptoServiceProvider();
    byte[] blockHash = md5.ComputeHash(buff);
    string convertedHash = Convert.ToBase64String(blockHash, 0, 16);
    blob.PutBlock(transferDetails[j].BlockId, new MemoryStream(buff), convertedHash, options);
    

    Rob,我真的很好奇您的代码在您的案例中是如何工作的,以及为什么它在我的案例中不起作用 - 它是特定于我机器上的设置的,还是 Azure 工具的不同版本(我是使用 v1.2)...如果您有任何想法,请告诉我。

    2) 开发存储中的一个错误:通过网络进行大量梳理后,我找到了this page,其中提到了开发存储中一个晦涩但显然已知的错误:

    如果两个请求尝试上传一个 阻塞到一个还没有的 blob 存在于开发存储中,一个 请求将创建 blob,并且 其他可能返回状态码 409 (冲突),与存储服务 错误代码 BlobAlreadyExists。

    这是我想出的解决方法:

    public static bool IsDevelopmentStorageRunning()
    {
        return new Microsoft.ServiceHosting.Tools.DevelopmentStorage.DevStore().IsRunning();
    }
    

    您需要添加对 Microsoft.ServiceHosting.Tools.dll 的引用,该引用位于“C:\Program Files\Windows Azure SDK\v1.2\bin”在我的机器上。然后,我在处理文件块的 Parallel.For 循环之前使用此方法,如下所示:

    bool isDevStorageRunning = StorageProxy.IsDevelopmentStorageRunning();
    ParallelOptions parallelOptions = new ParallelOptions();
    parallelOptions.MaxDegreeOfParallelism = isDevStorageRunning ? 1 : 4;
    Parallel.For(0, transferDetails.Length, parallelOptions, j => { ... });
    

    我希望这可以为某人省去我所经历的所有麻烦。 Rob,再次感谢您的帮助:)

    【讨论】:

      【解决方案2】:

      提申,

      看到这篇文章后,我回去重新测试了我的代码,我认为传递的数据有问题(可能是你传递给函数的内容?)。

      我立即跳出来的一件事是您提供的 md5 哈希...在我测试的每种情况下,我的 md5 哈希都以两个等号结尾,如下所示(从 fiddler 捕获):

      内容-MD5:D1Mxthoqhlwm9cC0729mWA==

      我不是加密专家,但我通过处理块 blob 的块 ID 知道,如果在将 blob ID 转换为 base64 编码值之前您的 blob ID 中有无效/不安全字符,您将获得无效数据并阻止 Azure 无法解释的 ID。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-02-26
        • 2014-08-19
        • 1970-01-01
        • 1970-01-01
        • 2016-08-23
        • 2021-07-09
        • 2017-04-17
        相关资源
        最近更新 更多