Лазурное хранилище таблиц возвращает 400 Bad Request
Я запускал это в режиме отладки, и я прикрепляю изображение с подробностями исключения. Как я могу узнать, что пошло не так? Я пытался вставить данные в таблицу. Не могу получить более подробную информацию?
Наблюдение: хранилище находится на Windows Azure не на моей машине. Таблицы были созданы, но я получаю эту ошибку при вставке данных
![enter image description here]()
// 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);
}
}
Ответы
Ответ 1
400 Ошибка означает, что что-то не так со значением одного из ваших свойств. Один из способов узнать - проследить запрос/ответ через Fiddler и посмотреть фактические данные, отправляемые в Windows Azure Storage.
Принимая дикие предположения, я предполагаю, быстро взглянув на ваш код, что в вашей модели у вас есть свойства типа Date/Time (OfflineTimestamp, OnlineTimestamp), и заметил, что в определенных сценариях один из них инициализируется значение по умолчанию, которое " DateTime.MinValue". Обратите внимание, что минимальное значение, разрешенное для атрибута типа Date/Time, составляет 1 января 1601 (UTC) в Windows Azure [ http://msdn.microsoft.com/en-us/library/windowsazure/dd179338.aspx]. Пожалуйста, посмотрите, не так ли. Если это так, то вы можете сделать их полями с нулевым типом, чтобы они не заполнялись значениями по умолчанию.
Посмотрите на Juha Palomäki ответ ниже, а также... там иногда есть несколько более полезное сообщение в исключении, где он предлагает (RequestInformation.ExtendedErrorInformation.ErrorMessage)
Ответ 2
В StorageException содержится также немного более подробная информация об ошибке.
Проверка отладки: StorageException.RequestInformation.ExtendedInformation
![enter image description here]()
Ответ 3
В моем случае это была косая черта в RowKey.
Я также получил "OutOfRangeInput" - один из входных данных запроса выходит за пределы диапазона. при попытке добавить вручную через эмулятор хранилища.
Символы, запрещенные в ключевых полях
Следующие символы недопустимы для значений для PartitionKey и RowKey:
- Символ прямой косой черты (/)
- Символ обратной косой черты (\)
- Символ номера ( #)
- Символ вопросительного знака (?)
- Управляющие символы от U + 0000 до U + 001F, включая:
- Символ горизонтальной вкладки (\t)
- Символ linefeed (\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
ну, в моем случае я пытался сделать это:
CloudBlobContainer container = blobClient.GetContainerReference("SessionMaterials");
await container.CreateIfNotExistsAsync();
из-за ContainerName SessionMaterials
(как привычка писать в Pascal Case и Camel Case: D) он вызывал 400 неправильных запросов. Итак, я просто должен сделать это sessionmaterials
. и это сработало.
Надеюсь, это кому-нибудь поможет.
PS: - Просто проверьте исключение http ответа или используйте fiddler для захвата запроса и ответа.
Ответ 5
Я столкнулся с той же проблемой, но причина в моем случае была связана с размером. После поиска дополнительных свойств исключений (RequestInformation.ExtendedErrorInformation) выяснилось, что:
ErrorCode: PropertyValueTooLarge
ErrorMessage: значение свойства превышает максимально допустимый размер (64 КБ). Если значением свойства является строка, то кодируется UTF-16, а максимальное количество символов должно быть 32 КБ или меньше.
Ответ 6
Иногда это потому, что ваш partitionKey
или rowKey
равен NULL
(это был случай для меня)
Ответ 7
в моем случае:
Название контейнера было написано заглавными буквами. существуют ограничения при использовании символов.
![введите описание изображения здесь]()
Ответ 8
Документацию от MS о всех кодах ошибок службы таблицы можно найти здесь
Ответ 9
У меня была та же ошибка BadRequest (400), в конце я заполняю вручную:
![enter image description here]()
И работал на меня. Надеюсь это поможет!
Ответ 10
Я также столкнулся с такой же проблемой. В моем случае значение PartitionKey не было установлено, поэтому по умолчанию значение PartitionKey было равно null, что привело к Object reference not set to an instance of an object.
exception
Убедитесь, что вы предоставили соответствующие значения для PartitionKey или RowKey, вы можете столкнуться с такой проблемой.
Ответ 11
Я исправил свои дела, и он отлично работал
Мои случаи:
- Строка строки не в правильном формате (400).
- Комбинация ключей разделов и строк не уникальна (409).
Ответ 12
Я получал 400 Bad Request, потому что я использовал ZRS (резервное хранилище зоны), а Google Analytics недоступна для этого типа хранилища. Я не знал, что использую Google Analytics.
Я удалил контейнер хранения и воссоздал его как GRS, и теперь он отлично работает.
Ответ 13
Я получил (400) неверный запрос, StatusMessage: неверный запрос, ErrorCode: OutOfRangeInput, когда у объекта было свойство DateTime не установлено (= DateTime.MinValue)
Ответ 14
В моем случае: я включил метаданные BLOB-объектов с именем тега, содержащим дефис.
var blob = container.GetBlockBlobReference(filename);
blob.Metadata.Add("added-by", Environment.UserName);
//.. other metadata
blob.UploadFromStream(filestream);
Проблема была в "added-by"
, и позже RTFM сказал мне, что имена тегов должны соответствовать соглашениям по идентификатору С#.
Ссылка: https://docs.microsoft.com/en-us/azure/storage/blobs/storage-properties-metadata
Подчеркивание работает отлично.
Ответ 15
В моем случае я не должен добавлять PartitionKey и Rowkey в мой класс сущности. Это должно быть из базового класса. Ниже будет просто работать.
public class TableRunLogMessage:TableEntity
{
public string status { get; set; }
public long logged { get; set; }
public TableRunLogMessage() { }
}
Ответ 16
Если вы используете 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.
Если вы на самом деле используете С#, как делает автор этого поста; Вы можете просто установить Fiddler и установить его на перехват. По умолчанию он должен перехватывать запросы. Вам также может понадобиться доверять сертификату Fiddler или иным образом делать эквивалент узла "NODE_TLS_REJECT_UNAUTHORIZED = 0".
Ответ 17
Я получил ответ 400-BadRequest от API таблицы учетной записи хранилища Azure. Информация об исключении показала, что "Доступ к учетной записи не поддерживает http.". Я подумал, что мы должны использовать https в строке подключения, когда в конфигурации учетной записи хранения включено "Безопасная передача требуется", как показано на рисунке ниже. ![enter image description here]()
Ответ 18
В моем случае для создания новой установки класса "TableBotDataStore" (среда MS bot) мы передаем параметр "tableName" с дефисом, например "master-bot", и TableBotDataStore может иметь имена таблиц только с буквами и цифрами
Ответ 19
У меня была та же проблема, функция передавала containerNameKey
как строку. ниже приведен код ошибки
container = blobClient.GetContainerReference(containerNameKey)
Я изменил его на
container = blobClient.GetContainerReference(ConfigurationManager.AppSettings(containerNameKey).ToString())
Это сработало