Azure Blob 下载(GET)导致 PUT 请求失败

Azure Blob download(GET) causes failed PUT request

我正在从 Azure blob 下载文件以将它们显示给我的用户。这些文件只是 doc/docx/pdf 格式的简历。这在几天前一直有效,我唯一做的就是更新 Azure SDK,所以这可能就是原因。 从客户端调用方法,最终调用这样的方法:

CloudBlobContainer container = GetContainer(containerName);
CloudBlockBlob blockBlob = container.GetBlockBlobReference(fileName);
blockBlob.Properties.ContentType = contentType;

using (var fileStream = new MemoryStream())
{
    await blockBlob.DownloadToStreamAsync(fileStream);
    return fileStream;
}

GetContainer方法定义如下:

try
{
    var storageAccount = StorageAccount;
    var blobClient = storageAccount.CreateCloudBlobClient();
    var container = blobClient.GetContainerReference(containerName);

    if (container.CreateIfNotExists())
    {
        container.SetPermissions(new BlobContainerPermissions
        {
             PublicAccess = BlobContainerPublicAccessType.Blob
        });
    }
    return container;
}
catch (Exception e)
{
    Logger.Error("GetBlobContainer fail", e);
}

截至昨天,我一直在 Azure Application Insights 中看到失败的依赖项调用。不是错误,只是失败的依赖项。每次下载文件时,都会执行GET请求,但同时不知为何也执行了PUT请求,都失败了。 在下图中,您可以看到此错误的 Insights 日志。每一个看起来都一样。调用方法,下载文件,然后调用 PUT 请求...

为什么要创建这个 PUT 请求,以及如何解决这个问题,这让我抓狂。同样有趣的是,据我所知,一切正常,而且我对 blob 的所有上传和下载调用都发生了这种情况。

PUT 请求由 container.CreateIfNotExists() 触发,当您的容器已经存在时,它应该会按预期失败。整个代码路径工作正常,我认为您无需担心任何事情。

container.CreateIfNotExists()的机制是Azure Storage Client Library会向服务器发送Put Container请求,如果是409(Conflict)则吞下错误,因为它表明容器已经存在。

如 8.0.0 版 release notes about Microsoft Azure Storage Libraries for .NET 中所述:

CreateIfNotExists methods will now only do one REST call instead of two.

这是我的测试,你可以参考它来更好地理解这个变化:

在版本 8.0.0 之前,CreateIfNotExists 会检查目标是否存在,如果不存在则创建资源,如下所示:

而在8.0.0版本之后,CreateIfNotExists会直接调用create方法,并用try-catch包裹这个操作来捕获异常。

综上所述,该问题是由于特定版本下Microsoft Azure Storage Libraries for .NET 发生了变化。您可以调用 CloudBlobContainer.Exist(),然后调用 CloudBlobContainer.Create() 而不是 CloudBlobContainer.CreateIfNotExists。但是此时,你需要用try-catch包裹CloudBlobContainer.Create()来自己捕获异常(例如有人创建了同名资源等)。

此外,您可以利用 ILSpy or ReSharper 检索有关 CloudBlobContainer.CreateIfNotExists 的更详细的实现。