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
的更详细的实现。
我正在从 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
的更详细的实现。