Azure Blob Error: StorageException: The condition specified using HTTP conditional header(s) is not met

Azure Blob Error: StorageException: The condition specified using HTTP conditional header(s) is not met

所以我有一个功能,可以每 10 分钟从 blob 存储中下载文本并检查结果。这个功能可以 运行 几天。但它经常(大约每天)在完成并出现以下错误之前失败。

Caused by: com.microsoft.azure.storage.StorageException: The condition specified using HTTP conditional header(s) is not met.

我的代码很简单。

public String downloadTextBlob(CloudBlobDirectory dir, String filename) {
    try {
        return dir.getBlockBlobReference(filename).downloadText();
    } catch (StorageException | IOException | URISyntaxException e) {
        throw new WorkbenchRuntimeException(e.getMessage(), e);
    }
}

我发布了同样的问题 here,我对讨论使用 OperationContext 解决问题的答案很感兴趣。但是问题不在 Java 上,答案也没有真正解释它实际上在做什么。

这是建议的解决方案(非 java 代码)

 OperationContext context = new OperationContext();
 context.SendingRequest += (sender, e) => { 
     e.Request.Headers["if-match"] = "*";
 };

谁能解释一下这到底是做什么的?也许我可以如何在 Java 中复制它,我注意到 Java azure 存储 sdk 中有一个 OperationContext,我可以调用 .downloadText() 并将操作上下文作为参数。我只是不确定如何处理 OperationContext。

首先,我建议您在此处阅读 Azure Blob 存储中的条件 headers:https://docs.microsoft.com/en-us/rest/api/storageservices/specifying-conditional-headers-for-blob-service-operations

我没有查看 Java SDK 的源代码,但我的猜测是 downloadText() 操作在幕后执行多个操作。在第一个操作中,它获取 blob 的属性(如 blob 的长度等),在下一个操作中它实际下载 blob。作为第一个操作的一部分,它还获取 blob 的 etag,并将相同的 etag 传递给 if-match header.

中的第二个操作

现在在第一次和第二次操作之间,blob 发生了一些变化,导致 etag 值发生变化。由于第二个请求仍然使用旧的 etag 值并且 etag 之间存在不匹配,因此您的请求失败 precondition failedif-match header 中存在 etag 指示存储服务执行操作 只有当 条件匹配(即 etag 匹配).由于 etag 不匹配,您会收到此错误。

要解决此问题,您需要使用以下 downloadText() 方法的替代方法:

downloadText(final String charsetName, final AccessCondition accessCondition, BlobRequestOptions options, OperationContext opContext)

并为 if-match 指定具有“*”值的访问条件,这实际上告诉存储服务忽略 etag 值。您可以在此处了解有关访问条件的更多信息:https://docs.microsoft.com/en-us/java/api/com.microsoft.azure.storage.accesscondition?view=azure-java-legacy.

您的代码类似于(未经测试的代码):

AccessCondition accessCondition = AccessCondition.generateIfMatchCondition("*");

并在您的 downloadText() 方法中使用此访问条件。