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之外,该图片并没有真正的帮助。“将”有帮助的是显示您执行的代码导致错误的请求:如何设置存储客户端,如何设置表,然后去插入等
David Makogon

我复制粘贴了代码。希望这会
Ryan

如果您说几种情况中的哪一种失败,将会很有帮助。同样,您显然是在此代码之外设置了一些属性(例如PartitionKey和RowKey),这样有助于了解这些属性以及它们将被设置为什么。
Brian Reischl

我注意到,当首先引发异常时,没有“查看详细信息”选项,但是当您继续调试并且流程返回到调用方时(再次弹出异常),您可以看到“查看详细信息”选项。从那里您可以使用@JuhaPalomäki的答案来查找错误
raghav710

Answers:


148

400错误表示您的其中一个属性的值有问题。一种查找方法是通过Fiddler跟踪请求/响应,并查看发送到Windows Azure存储的实际数据。

做出一个大胆的猜测,我假设快速浏览一下您的代码,即在您的模型中您具有一些Date / Time类型属性(OfflineTimestamp,OnlineTimestamp),并观察到在某些情况下,其中一个已使用默认值初始化。是“ DateTime.MinValue ”。请注意,允许的日期/时间类型的属性最小值为1601年1月1日(UTC)在Windows Azure中[http://msdn.microsoft.com/en-us/library/windowsazure/dd179338.aspx] 。请查看情况是否如此。如果是这种情况,则可以将它们设置为可为空的类型字段,以使它们不会填充默认值。

看看下面的JuhaPalomäki的答案...有时在他建议的例外情况下会有一条稍微有用的消息(RequestInformation.ExtendedErrorInformation.ErrorMessage)


259
为了赢得上帝的爱,如果Azure团队的某人阅读了此内容,请使SDK返回比400 Bad Request错误更多的信息。我不知道为什么表存储中的DateTime不能与.NET DateTime对象具有相同的最小日期,但是我浪费了这一天的美好时光。当我确定是哪个财产引起问题时,我也碰巧遇到了这个问题,这有所帮助。现在,在插入/更新带有DateTime的表存储模型之前,我必须对所有DateTime属性进行检查。不理想...-
迈克尔

8
当我们使用它时,您也不能拥有枚举属性。我不得不将财产转换为Integer
Martin

15
显然,表名也不能带有连字符。花了我一个小时来解决这个问题。
Amogh Natu 2015年

4
表名也不能带有下划线。这就是为什么我在这里
Quango 2015年

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-请求输入之一超出范围”。尝试通过存储模拟器手动添加时发生错误。

关键字段中不允许使用的字符

PartitionKeyRowKey属性的值中不允许使用以下字符 :

  • 正斜线(/)字符
  • 反斜杠(\)字符
  • 数字符号()字符
  • 问号()字符
  • 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
我喜欢扩展方法。救了我。
Newton Sheikh

这里给出替代响应这确实正则表达式替换stackoverflow.com/a/28788382/285795
ΩmegaMan

为我修复。我有一个正斜线。看起来好像是伪复合键的好角色。
理查德

此扩展方法不会删除不允许的几个字符。如:空间, “(”, “)” ... docs.microsoft.com/en-us/rest/api/storageservices/...
蒂亚戈·安德拉德-席尔瓦

6

我遇到了同样的问题,但我的情况是由于尺寸而引起的。在深入研究其他异常属性(RequestInformation.ExtendedErrorInformation)之后,找到了原因:

错误代码:PropertyValueTooLarge错误消息:属性值超出了允许的最大大小(64KB)。如果属性值为字符串,则它是UTF-16编码的,最大字符数应为32K或更少。


5

好吧,就我而言,我正在尝试这样做:

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

由于ContainerName SessionMaterials(习惯在Pascal Case和Camel Case:D中编写),它导致了400个错误的请求。所以,我只需要做到sessionmaterials。而且有效。

希望这可以帮助一些人。

PS:-只需检查异常http响应或使用Fiddler捕获请求和响应。





1

我遇到了同样的BadRequest(400)错误,最后我手动填写了:

在此处输入图片说明

为我工作。希望这可以帮助!


这个答案是正确的。我浪费了大约一个小时,但发现甚至Timestamp必须手动生成。真烦人。
罗曼·科拉达

0

我也面临同样的问题。在我的情况下,未设置PartitionKey值,因此默认情况下PartitionKey值为null,这导致Object reference not set to an instance of an object.异常

检查您是否为PartitionKey或RowKey提供了适当的值,您可能会遇到这样的问题。


0

我整理好箱子,效果很好

我的情况:

  1. 行键的格式不正确(400)。
  2. 分区键和行键的组合不是唯一的(409)。

0

我收到400错误的请求,因为我使用的是ZRS(区域冗余存储),而Analytics(分析)无法用于这种类型的存储。我不知道自己在使用Analytics(分析)。

我删除了存储容器,并重新创建为GRS,现在可以正常使用了。


0

当实体未设置属性DateTime(= DateTime.MinValue)时,我收到(400)错误请求,StatusMessage:错误请求,ErrorCode:OutOfRangeInput


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/zh-cn/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的“ NODE_TLS_REJECT_UNAUTHORIZED = 0”。


0

我从Azure存储帐户表API得到了400-BadRequest响应。异常信息显示“正在访问的帐户不支持http。”。我认为在存储帐户配置中启用了“需要安全传输”时,必须在连接字符串中使用https,如下图所示。在此处输入图片说明


0

在我的案例中,创建“ TableBotDataStore”类的新设备(MS bot框架),我们将带有连字符的“ tableName”参数传递给“ master-bot”,并且TableBotDataStore只能使用字母和数字表示表名


0

我有同样的问题,该函数正在传递containerNameKeyas字符串。下面是给出错误的代码

container = blobClient.GetContainerReference(containerNameKey) 

我将其更改为

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

有效

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.