【问题标题】:Azure Blob download(GET) causes failed PUT requestAzure Blob 下载 (GET) 导致 PUT 请求失败
【发布时间】:2017-05-26 11:12:28
【问题描述】:

我正在从 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 的所有上传和下载调用中。

【问题讨论】:

  • 为什么要返回已处理的fileStream?这不会造成问题吗?你用这个值做什么?
  • 我正在返回它并使用 ToArray() 方法从中读取字节数组。关闭/处理流后字节数组仍然可用 (stackoverflow.com/questions/3981253/…)

标签: c# azure dependencies azure-blob-storage


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    正如release notes 中提到的关于版本 8.0.0 的 Microsoft Azure Storage Libraries for .NET

    CreateIfNotExists 方法现在只会执行一次 REST 调用,而不是两次。

    这是我的测试,您可以参考它以更好地了解此更改:

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

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

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

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

    【讨论】:

    • 谢谢布鲁斯,这回答了我的问题。我只是不喜欢在控制台中看到一堆错误,所以我想我会将代码更改为单独的调用。
    • 不需要尝试/捕获。如果 Exists() 返回 false,则调用 CreateIfNotExists()。但也要考虑完全避免调用。如果容器不存在,那么 blob 也不存在,那么为什么要额外往返服务?
    猜你喜欢
    • 2021-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-23
    • 1970-01-01
    • 2018-08-25
    • 2021-11-05
    • 2013-01-15
    相关资源
    最近更新 更多