Хранилище таблиц Azure возвращает 400 неверных запросов


119

Я запустил это в режиме отладки и прикрепляю изображение с деталями исключения. Как я могу узнать, что пошло не так? Я пытался вставить данные в таблицу. Разве лазурь не может дать мне более подробную информацию?

Замечания: Хранилище находится в Windows Azure, а не на моем компьютере. Таблицы были созданы, но я получаю эту ошибку при вставке данных

введите описание изображения здесь

// Retrieve the storage account from the connection string.
Microsoft.WindowsAzure.Storage.CloudStorageAccount storageAccount = Microsoft.WindowsAzure.Storage.CloudStorageAccount.Parse("DefaultEndpointsProtocol=https;AccountName=***;AccountKey=***");

// Create the table client.
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();

// Create the table if it doesn't exist.
CloudTable table = tableClient.GetTableReference("EmployeeOnlineHistory");
table.CreateIfNotExists();

и вот код вставки:

public static void SetStatus(Employee e, bool value)
{
    try
    {
        // Retrieve the storage account from the connection string.
        Microsoft.WindowsAzure.Storage.CloudStorageAccount storageAccount = Microsoft.WindowsAzure.Storage.CloudStorageAccount.Parse("DefaultEndpointsProtocol=https;AccountName=###;AccountKey=###");

        // Create the table client.
        CloudTableClient tableClient = storageAccount.CreateCloudTableClient();

        // Create the CloudTable object that represents the "people" table.
        CloudTable table = tableClient.GetTableReference("EmployeeOnlineHistory");

        // Create a new customer entity.

        if (value == true)
        {
            EmployeeOnlineHistory empHistory = new EmployeeOnlineHistory(e.Id);
            empHistory.IsOnline = true;
            empHistory.OnlineTimestamp = DateTime.Now;
            TableOperation insertOperation = TableOperation.Insert(empHistory);
            table.Execute(insertOperation);
        }
        else
        {
            TableQuery<EmployeeOnlineHistory> query = new TableQuery<EmployeeOnlineHistory>()
                .Where(TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, e.Id.ToString()));
            EmployeeOnlineHistory entity = table.ExecuteQuery(query).Take(1).FirstOrDefault();

            if ((entity!=null)&&(entity.IsOnline))
            {
                entity.IsOnline = false;
                entity.OfflineTimestamp = DateTime.Now;
                entity.OnlineTime = (entity.OfflineTimestamp - entity.OnlineTimestamp);
                TableOperation updateOperation = TableOperation.Replace(entity);
                table.Execute(updateOperation);
            }
            else
            {
                EmployeeOnlineHistory empHistory = new EmployeeOnlineHistory(e.Id);
                empHistory.IsOnline = false;
                empHistory.OfflineTimestamp = DateTime.Now;
                TableOperation insertOperation = TableOperation.Insert(empHistory);
                table.Execute(insertOperation);
            }
        }
    }
    catch (Exception ex)
    {
        //var details = new System.IO.StreamReader(((Microsoft.WindowsAzure.Storage.StorageException)ex)..Response.GetResponseStream()).ReadToEnd();
        LogFile.Error("EmployeeOnlineHistory.setStatus",ex);
    }
}

Это изображение на самом деле не помогает, кроме подтверждения ошибки 400. "Помогло бы" показать код, который вы выполнили, что привело к неверному запросу: как вы настраиваете клиент хранилища, как вы настраиваете таблицу, а затем переходите вставить и т. д.
Дэвид Макогон

Я скопировал код. Надеюсь, это поможет
Райан

Было бы полезно, если бы вы сказали, какой из нескольких случаев терпит неудачу. Кроме того, очевидно, что вы устанавливаете некоторые свойства за пределами этого кода (например, PartitionKey и RowKey), поэтому было бы полезно узнать, что это такое и для чего они установлены.
Брайан Райшл,

Я заметил, что когда сначала создается исключение, опция «Просмотр подробностей» отсутствует, но когда вы продолжаете отладку и поток возвращается к вызывающему (где снова появляется исключение), вы можете увидеть параметр «Просмотр подробностей». Оттуда вы можете использовать ответ @Juha Palomäki, чтобы найти ошибку
raghav710

Ответы:


148

Ошибка 400 означает, что что-то не так со значением одного из ваших свойств. Один из способов узнать это - отследить запрос / ответ через Fiddler и увидеть фактические данные, отправляемые в хранилище Windows Azure.

Делая безумное предположение, я предполагаю, быстро взглянув на ваш код, что в вашей модели у вас есть некоторые свойства типа Date / Time (OfflineTimestamp, OnlineTimestamp), и заметил, что в определенных сценариях один из них инициализируется значением по умолчанию, которое " DateTime.MinValue ". Обратите внимание, что минимальное допустимое значение для атрибута типа «Дата / время» - 1 января 1601 г. (UTC) в Windows Azure [http://msdn.microsoft.com/en-us/library/windowsazure/dd179338.aspx] . Пожалуйста, посмотри, если это не так. В этом случае вы можете сделать их полями типа, допускающими значение NULL, чтобы они не заполнялись значениями по умолчанию.

Взгляните на ответ Юхи Паломяки ниже ... иногда бывает немного более полезное сообщение в исключении, где он предлагает (RequestInformation.ExtendedErrorInformation.ErrorMessage)


259
Слава Богу, если кто-то из команды Azure прочитает это, пожалуйста, сделайте так, чтобы SDK возвращал больше информации, чем ошибка 400 Bad Request. Я понятия не имею, почему DateTime в хранилище таблиц не может иметь ту же минимальную дату, что и объект .NET DateTime, но я потратил на это хороший день. К тому времени, когда я дошел до того, какое свойство вызвало проблему, я тоже наткнулся на это, что помогло. Теперь, прежде чем я когда-либо вставляю / обновляю модель с DateTime для хранения таблиц, я должен выполнить проверки всех свойств DateTime. НЕ идеально ...
Майкл

8
Пока мы это делаем, у вас также не может быть свойства enum. Мне пришлось преобразовать свойство в целое число
Мартин

15
Судя по всему, имена таблиц тоже не могут иметь дефисов. Мне потребовался час, чтобы понять это.
Amogh Natu

4
Имена таблиц не могут иметь подчеркивания .. вот почему я здесь
Куанго

2
Я предполагаю, что RowKey не инициализируется пустой строкой, так как это основное значение поиска и только индексированный столбец ... это напоминание вам о его заполнении, я бы подумал ... это только мое предположение ... имена таблиц идут ... прочтите это ... blogs.msdn.microsoft.com/jmstall/2014/06/12/…
dreadeddev

129

StorageException также содержит более подробную информацию об ошибке.

Проверьте отладчик: StorageException.RequestInformation.ExtendedInformation

введите описание изображения здесь


6
Почему эта информация не является исключением верхнего уровня?
Wilko van der Veen

Для меня это выделено .. «Добавить blob не поддерживается эмулятором» .. FML
Michiel Cornille

The specifed resource name contains invalid characters.в имени моей таблицы были тире ... как и в именах моей очереди ... вздох. Надеюсь, поиск подберет это для большего количества людей! см .: stackoverflow.com/questions/45305556/…
Nateous

55

В моем случае это была косая черта в RowKey .

Я также получил OutOfRangeInput - один из входных данных запроса вне допустимого диапазона. ошибка при попытке добавить вручную через эмулятор хранилища.

Символы, запрещенные в ключевых полях

Следующие символы не допускаются в значениях свойств PartitionKey и RowKey :

  • Косая черта ( / )
  • Символ обратной косой черты ( \ )
  • Знак номера ( # )
  • Знак вопроса ( ? )
  • Управляющие символы от U + 0000 до U + 001F , включая:
    • Символ горизонтальной табуляции ( \ t )
    • Символ перевода строки ( \ n )
    • Символ возврата каретки ( \ r )
    • Управляющие символы от U + 007F до U + 009F

http://msdn.microsoft.com/en-us/library/dd179338.aspx

Я написал метод расширения, чтобы справиться с этим за меня.

public static string ToAzureKeyString(this string str)
{
    var sb = new StringBuilder();
    foreach (var c in str
        .Where(c => c != '/'
                    && c != '\\'
                    && c != '#'
                    && c != '/'
                    && c != '?'
                    && !char.IsControl(c)))
        sb.Append(c);
    return sb.ToString();
}

4
Это тоже была моя проблема. Ваш метод расширения работает как чемпион!
Джеймс Уилсон

1
Мне понравился метод расширения. Спас меня.
Ньютон Шейх


Исправил для меня. У меня была косая черта. Похоже, хороший символ для псевдосложного ключа.
Ричард

Этот метод расширения не удаляет несколько недопустимых символов. Например: пробел, "(", ")" ... docs.microsoft.com/en-us/rest/api/storageservices/…
Тиаго Андраде и Силва,

6

Я столкнулся с той же проблемой, но в моем случае причина была в размере. Покопавшись в дополнительных свойствах исключения (RequestInformation.ExtendedErrorInformation), нашел причину:

ErrorCode: PropertyValueTooLarge ErrorMessage: значение свойства превышает максимально допустимый размер (64 КБ). Если значение свойства является строкой, она закодирована в UTF-16, а максимальное количество символов должно быть не более 32 КБ.


5

ну, в моем случае я пытался это сделать:

CloudBlobContainer container = blobClient.GetContainerReference("SessionMaterials");
await container.CreateIfNotExistsAsync();

из-за ContainerName SessionMaterials(по привычке писать в Pascal Case и Camel Case: D) он вызывал 400 неверных запросов. Так что мне просто нужно это сделать sessionmaterials. и это сработало.

Надеюсь, это кому-то поможет.

PS: - Просто проверьте HTTP-ответ исключения или используйте скрипач для захвата запроса и ответа.


3

в моем случае: имя контейнера было заглавной буквой. есть ограничения при использовании символов. введите описание изображения здесь


Это касается и имен свойств таблиц.
Иэн Баллард

3

Иногда это потому , что ваш partitionKeyили rowKeyявляетсяNULL

(это было для меня)


1

Документацию от MS обо всех кодах ошибок службы таблиц можно найти здесь


1

У меня была такая же ошибка BadRequest (400), в конце заполняю вручную:

введите описание изображения здесь

И работал у меня. Надеюсь это поможет!


Это правильный ответ. Я потратил около часа, и это не значит, что даже Timestampнужно сгенерировать вручную. Это действительно раздражает.
Роман Коляда

0

Я тоже столкнулся с такой же проблемой. В моем случае значение PartitionKey не было установлено, поэтому по умолчанию значение PartitionKey было нулевым, что привело к Object reference not set to an instance of an object.исключению

Проверьте, указываете ли вы соответствующие значения для PartitionKey или RowKey, вы можете столкнуться с такой проблемой.


0

Я исправил свои случаи, и все заработало

Мои кейсы:

  1. Ключ строки имеет неправильный формат (400).
  2. Комбинация ключа раздела и ключа строки не уникальна (409).

0

Я получал 400 неверных запросов, потому что я использовал ZRS (Zone Redundant Storage), а аналитика недоступна для этого типа хранилища. Я не знал, что использую Google Analytics.

Я удалил контейнер для хранения и воссоздал его как GRS, и теперь он работает нормально.


0

Я получал (400) неверный запрос, StatusMessage: Bad Request, ErrorCode: OutOfRangeInput, когда у объекта было свойство DateTime не установлено (= DateTime.MinValue)


0

В моем случае: я включил метаданные blob с именем тега, содержащим дефис.

var blob = container.GetBlockBlobReference(filename);
blob.Metadata.Add("added-by", Environment.UserName);
//.. other metadata
blob.UploadFromStream(filestream);

"added-by"Проблемой был дефис , и позже RTFM сказал мне, что имена тегов должны соответствовать соглашениям об идентификаторах C #.

Ссылка: https://docs.microsoft.com/en-us/azure/storage/blobs/storage-properties-metadata

Подчеркивание работает нормально.


0

В моем случае я не должен добавлять PartitionKey и Rowkey в свой класс сущности. Он должен быть из базового класса. Ниже будет просто работать.

public class TableRunLogMessage:TableEntity
{
      public string status { get; set; }
      public long logged { get; set; }


      public TableRunLogMessage() { }
}

0

Если вы используете NodeJS и наткнулись на этот пост только для того, чтобы обнаружить, что вы не получаете такой прекрасной подробной информации в своем объекте ошибки; вы можете использовать прокси для получения этих данных. Однако, поскольку здесь никто не упоминает, КАК использовать прокси.

Самый простой способ с NodeJS - установить две переменные среды:

NODE_TLS_REJECT_UNAUTHORIZED=0
This disables SSL checks so you can intercept your own SSL requests. This leaves you open to Man-in-The-Middle attacks and should NEVER make it to production, and I wouldn't even leave it in development for long. However, it will allow you to intercept the HTTP Requests.

HTTP_PROXY=http://127.0.0.1:8888
This sets node to utilize a proxy listening on your localhost at port 8888. Port 8888 is the default for Fiddler. Many other proxies default to 8080.

Если вы действительно используете C #, как это делает автор этой статьи; вы можете просто установить Fiddler и настроить его на перехват. По умолчанию он должен перехватывать запросы. Возможно, вам также потребуется доверять сертификату Fiddler или иным образом выполнить эквивалент узла «NODE_TLS_REJECT_UNAUTHORIZED = 0».


0

Я получил ответ 400-BadRequest от API таблицы учетных записей хранения Azure. Информация об исключении показала, что «Учетная запись, к которой осуществляется доступ, не поддерживает http.». Я решил, что мы должны использовать https в строке подключения, когда в конфигурации учетной записи хранения включен параметр «Требуется безопасная передача», как показано на изображении ниже.введите описание изображения здесь


0

В моем случае для создания нового экземпляра класса «TableBotDataStore» (фреймворк MS-ботов) мы передаем параметр «tableName» с дефисом, например «master-bot», а TableBotDataStore может иметь имена таблиц только с буквами и цифрами.


0

У меня была такая же проблема, функция передавала containerNameKeyстроку as. ниже приведен код, который дал ошибку

container = blobClient.GetContainerReference(containerNameKey) 

Я изменил это на

container = blobClient.GetContainerReference(ConfigurationManager.AppSettings(containerNameKey).ToString()) 

Это сработало

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.