为了实现 Azure 存储 blob 的乐观并发,我正在根据 blob 属性中的 ETag 值构造一个If-Match 访问条件。
如果另一个进程更新了 Blob,则 Blob 服务应返回 HTTP 412(前提条件失败(状态消息。但是,该服务始终返回此 412 状态。
对于此示例,我已使用存储资源管理器手动查找 ETag 值。
重现问题的最小代码片段是:
var storage = CloudStorageAccount.Parse(connectionString);
var blobClient = storage.CreateCloudBlobClient();
var container = blobClient.GetContainerReference("foo");
var blob = container.GetBlockBlobReference("foo/1");
await blob.UploadTextAsync(
"test",
Encoding.UTF8,
AccessCondition.GenerateIfMatchCondition(""0x1A52537587A1234""),
new BlobRequestOptions(),
null);
问题是我不小心使用了错误的blobName
:
var blob = container.GetBlockBlobReference("foo/1");
那应该是:
var blob = container.GetBlockBlobReference("1");
否则,ETag 检查将正确失败,因为没有名称为foo/1
的 blob。
上传具有特定ETAG
值的 blob 时,它将首次工作。但是,当您第二次上传具有相同ETAG
的 blob 时,它将引发 412 错误。因为一旦操作 Blob,其ETAG
就会更新。
Blob 和容器的乐观并发
对此类对象执行更新的用户可以发送原始ETag
以及条件标头,以确保仅在满足特定条件时才会发生更新 - 在这种情况下,条件是一个If-Match
标头,它要求存储服务确保更新请求中指定的ETag
值与存储服务中存储的值相同。
// Retrieve Etag from the response of an earlier UploadText blob operation.
string orignalETag = blockBlob.Properties.ETag;
// This code simulates an update by a third party.
string helloText = "Blob updated by a third party.";
// No etag, provided so orignal blob is overwritten (thus generating a new etag)
blockBlob.UploadText(helloText);
Console.WriteLine("Blob updated. Updated ETag = {0}", blockBlob.Properties.ETag);
// Now try to update the blob using the orignal ETag provided when the blob was created
try
{
Console.WriteLine("Trying to update blob using orignal etag to generate if-match access condition");
blockBlob.UploadText(helloText,accessCondition:
AccessCondition.GenerateIfMatchCondition(orignalETag));
}
catch (StorageException ex)
{
if (ex.RequestInformation.HttpStatusCode == (int)HttpStatusCode.PreconditionFailed)
{
Console.WriteLine("Precondition failure as expected. Blob's orignal etag no longer matches");
}
}
有关更多详细信息,您可以参考本文。