Ошибка большого двоичного объекта Azure: StorageException: условие, указанное с помощью условных заголовков HTTP, не выполнено

Итак, у меня есть функция, которая просто загружает текст из хранилища BLOB-объектов каждые 10 минут и проверяет результат. Эта функция может работать в течение нескольких дней. Но он часто (примерно каждый день) терпит неудачу, прежде чем закончить со следующей ошибкой.

Причина: com.microsoft.azure.storage.StorageException: условие, указанное с помощью условных заголовков HTTP, не выполняется.

Мой код довольно прост.

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

Я опубликовал ту же проблему здесь, и меня заинтересовал ответ, в котором говорилось об использовании OperationContext для решения проблемы. Но вопрос был не о Java, и ответ на самом деле не объяснял, что он на самом деле делает.

Вот предлагаемое решение (не java-код)

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

Может ли кто-нибудь объяснить, что это на самом деле делает? И, возможно, как я могу воспроизвести это в Java, я заметил, что в SDK хранилища Azure Azure есть OperationContext, и что я могу вызвать .downloadText() с контекстом операции в качестве параметра. Я просто не уверен, что делать с OperationContext.


person OneTwo    schedule 10.06.2020    source источник
comment
Возможно ли, что содержимое большого двоичного объекта изменилось во время выполнения операции загрузки?   -  person Gaurav Mantri    schedule 10.06.2020
comment
Да, безусловно.   -  person OneTwo    schedule 10.06.2020


Ответы (1)


Во-первых, я бы посоветовал вам прочитать об условных заголовках в хранилище BLOB-объектов Azure здесь: https://docs.microsoft.com/en-us/rest/api/storageservices/specifying-conditional-headers-for-blob-service-operations .

Я не просматривал исходный код Java SDK, но предполагаю, что операция downloadText() выполняет несколько операций за кулисами. В первой операции он получает свойства большого двоичного объекта (например, длину большого двоичного объекта и т. д.), а в следующей операции он фактически загружает большой двоичный объект. В рамках первой операции он также получает etag большого двоичного объекта и передает тот же etag второй операции в заголовке if-match.

Теперь между 1-й и 2-й операцией что-то изменилось с большим двоичным объектом, что привело к изменению значения etag. Поскольку во втором запросе по-прежнему использовалось старое значение etag, а между etag есть несоответствие, ваш запрос завершается с ошибкой precondition failed. Наличие etag в заголовке if-match указывает службе хранилища выполнять операцию только если условие соответствует (т. е. 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().

person Gaurav Mantri    schedule 10.06.2020
comment
у меня та же проблема, но проблема в том, что я использую BlobTrigger. мы можем сделать это if-match в этом случае? - person Raas Masood; 07.08.2020