Bộ nhớ bảng Azure trả về 400 Yêu cầu Không hợp lệ


119

Tôi đã chạy điều này ở chế độ gỡ lỗi và tôi đính kèm một hình ảnh với các chi tiết của ngoại lệ. Làm thế nào tôi có thể biết những gì đã xảy ra? Tôi đang cố gắng đưa dữ liệu vào bảng. Azure không thể cho tôi biết thêm chi tiết?

Ám ảnh: Bộ nhớ trên Windows Azure không có trên máy của tôi. Các bảng đã được tạo, nhưng tôi gặp lỗi này khi chèn dữ liệu

nhập mô tả hình ảnh ở đây

// 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();

và đây là mã chèn:

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);
    }
}

Hình ảnh đó không thực sự giúp ích gì, ngoài việc xác nhận lỗi 400. Liệu "sẽ" giúp ích gì là hiển thị mã bạn đã thực thi dẫn đến yêu cầu xấu: cách bạn thiết lập ứng dụng khách lưu trữ, cách bạn thiết lập bảng, sau đó để chèn, v.v.
David Makogon

Tôi đã sao chép-dán mã. Hy vọng điều này sẽ hữu ích
Ryan

Sẽ hữu ích nếu bạn cho biết trường hợp nào không thành công. Ngoài ra, dường như bạn đang thiết lập một số thuộc tính bên ngoài mã này (ví dụ: PartitionKey và RowKey) vì vậy sẽ giúp biết được những thuộc tính đó là gì và chúng đang được đặt thành gì.
Brian Reischl

Tôi nhận thấy rằng khi Ngoại lệ được ném trước, không có tùy chọn "Xem chi tiết" nhưng khi bạn tiếp tục gỡ lỗi và quy trình quay trở lại trình gọi (nơi ngoại lệ bật lên một lần nữa), bạn có thể thấy tùy chọn Xem chi tiết. Từ đó bạn có thể sử dụng câu trả lời @Juha Palomäki 's để tìm ra lỗi
raghav710

Câu trả lời:


148

Lỗi 400 có nghĩa là có điều gì đó không ổn với giá trị của một trong các thuộc tính của bạn. Một cách để tìm hiểu là theo dõi yêu cầu / phản hồi thông qua Fiddler và xem dữ liệu thực tế đang được gửi đến Windows Azure Storage.

Suy đoán lung tung, tôi giả định bằng cách xem nhanh mã của bạn rằng trong mô hình của bạn, bạn có một số thuộc tính kiểu Ngày / Giờ (Dấu ngoại tuyến, Dấu thời gian trực tuyến) và quan sát thấy rằng trong một số trường hợp nhất định, một trong số chúng được khởi tạo với giá trị mặc định là " DateTime.MinValue ". Xin lưu ý rằng giá trị tối thiểu được phép cho thuộc tính loại Ngày / Giờ là ngày 1 tháng 1 năm 1601 (UTC) trong Windows Azure [http://msdn.microsoft.com/en-us/library/windowsazure/dd179338.aspx] . Hãy xem nếu không phải vậy. Nếu đúng như vậy, thì bạn có thể đặt chúng là các trường kiểu nullable để chúng không bị điền các giá trị mặc định.

Hãy xem câu trả lời của Juha Palomäki bên dưới ... đôi khi có một thông điệp hữu ích hơn một chút trong trường hợp ngoại lệ mà anh ấy gợi ý (RequestInformation.ExtendedErrorInformation.ErrorMessage)


259
Vì tình yêu của Chúa, nếu ai đó trong nhóm Azure đọc được điều này, vui lòng làm cho SDK trả về nhiều thông tin hơn lỗi 400 Bad Request. Tôi không biết tại sao DateTime trong bảng lưu trữ không thể có cùng ngày tối thiểu như đối tượng .NET DateTime, nhưng tôi đã lãng phí một ngày tốt lành cho điều này. Vào thời điểm tôi nhận ra tài sản nào gây ra vấn đề, tôi cũng đã xảy ra vấn đề này, điều này đã giúp ích. Bây giờ, trước khi tôi chèn / cập nhật một mô hình với DateTime để lưu trữ bảng, tôi phải chạy kiểm tra trên tất cả các thuộc tính DateTime. KHÔNG lý tưởng ...
Michael

8
Trong khi chúng tôi ở đó, bạn cũng không thể có tài sản enum. Tôi phải sở hữu chuyển đổi sang Integer
Martin

15
Rõ ràng, tên bảng cũng không thể có dấu gạch nối. Tôi mất một giờ để tìm ra điều đó.
Amogh Natu

4
Tên bảng cũng không được có dấu gạch dưới .. đó là lý do tại sao tôi ở đây
Quango

2
Tôi tưởng tượng RowKey không được khởi tạo với chuỗi trống vì đây là giá trị tra cứu chính và chỉ cột được lập chỉ mục ... nó để nhắc bạn điền nó mà tôi có thể nghĩ .... đây chỉ là suy đoán của tôi ... Theo như tên bảng đi .. có một chi của này ... blogs.msdn.microsoft.com/jmstall/2014/06/12/...
dreadeddev

129

StorageException cũng chứa thông tin chi tiết hơn một chút về lỗi.

Kiểm tra trình gỡ lỗi: StorageException.RequestInformation.ExtendedInformation

nhập mô tả hình ảnh ở đây


6
Tại sao thông tin này không phải là ngoại lệ cấp cao nhất?
Wilko van der Veen

Đối với tôi đây nhấn mạnh .. "Nối blob không được hỗ trợ bởi giả lập" .. FML
Michiel Cornille

The specifed resource name contains invalid characters.tên bảng của tôi có dấu gạch ngang trong đó ... giống như tên hàng đợi của tôi ... thở dài. Hy vọng rằng tìm kiếm sẽ chọn được điều này cho nhiều người hơn! xem: stackoverflow.com/questions/45305556/…
Nateous

55

Trong trường hợp của tôi, đó là một dấu gạch chéo trong RowKey .

Tôi cũng nhận được 'OutOfRangeInput - Một trong những đầu vào yêu cầu nằm ngoài phạm vi.' khi cố gắng thêm thủ công thông qua trình mô phỏng lưu trữ.

Các ký tự không được phép trong các trường chính

Các ký tự sau không được phép trong các giá trị cho các thuộc tính PartitionKeyRowKey :

  • Dấu gạch chéo lên ( / )
  • Ký tự dấu gạch chéo ngược ( \ )
  • Ký tự dấu số ( # )
  • Ký tự dấu chấm hỏi ( ? )
  • Các ký tự điều khiển từ U + 0000 đến U + 001F , bao gồm:
    • Ký tự tab ngang ( \ t )
    • Ký tự trong nguồn cấp dữ liệu ( \ n )
    • Ký tự xuống dòng ( \ r )
    • Điều khiển các ký tự từ U + 007F đến U + 009F

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

Tôi đã viết một phương thức mở rộng để xử lý điều này cho tôi.

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
Đây cũng là vấn đề của tôi. Phương thức mở rộng của bạn hoạt động như một nhà vô địch!
James Wilson

1
Tôi yêu thích Phương pháp mở rộng. Cứu tôi.
Newton Sheikh

Phản hồi thay thế được đưa ra ở đây thực hiện một regex thay thế stackoverflow.com/a/28788382/285795
ΩmegaMan

Đã sửa nó cho tôi. Tôi đã có một dấu gạch chéo. Có vẻ như một ký tự tốt cho một khóa ghép giả.
richard

Phương thức mở rộng này không loại bỏ một số ký tự không được phép. Ví dụ: dấu cách, "(", ")" ... docs.microsoft.com/en-us/rest/api/storageservices/…
Tiago Andrade e Silva

6

Tôi gặp phải vấn đề tương tự nhưng lý do trong trường hợp của tôi là do kích thước. Sau khi đào sâu vào các thuộc tính ngoại lệ bổ sung (RequestInformation.ExtendedErrorInformation), tìm thấy lý do:

ErrorCode: PropertyValueTooLarge ErrorMessage: Giá trị thuộc tính vượt quá kích thước tối đa cho phép (64KB). Nếu giá trị thuộc tính là một chuỗi thì nó được mã hóa UTF-16 và số ký tự tối đa phải là 32K trở xuống.


5

tốt, trong trường hợp của tôi, tôi đã cố gắng làm điều này:

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

vì ContainerName SessionMaterials(như một thói quen viết trong Pascal Case và Camel Case: D) nó đã gây ra 400 yêu cầu xấu. Vì vậy, tôi chỉ cần làm cho nó sessionmaterials. va no đa hoạt động.

Hy vọng điều này sẽ giúp một số người.

Tái bút: - Chỉ cần kiểm tra phản hồi http ngoại lệ hoặc sử dụng fiddler để nắm bắt yêu cầu và phản hồi.


3

trong trường hợp của tôi: Tên vùng chứa được viết hoa. có những hạn chế khi sử dụng ký tự. nhập mô tả hình ảnh ở đây


Điều này cũng áp dụng cho các tên thuộc tính bảng.
Iain Ballard

3

Đôi khi là do bạn partitionKeyhoặc rowKeyNULL

(đó là trường hợp của tôi)


1

Bạn có thể tìm thấy tài liệu từ MS về tất cả Mã lỗi dịch vụ bảng tại đây


1

Tôi đã gặp lỗi BadRequest (400) tương tự, ở phần cuối, tôi điền theo cách thủ công:

nhập mô tả hình ảnh ở đây

Và đã làm việc cho tôi. Hi vọng điêu nay co ich!


Câu trả lời này là chính xác. Tôi đã lãng phí khoảng một giờ và nó cho thấy rằng thậm chí Timestampphải được tạo thủ công. Nó thực sự phiền phức.
Roman Koliada

0

Tôi cũng phải đối mặt với cùng một loại vấn đề. Trong trường hợp của tôi, giá trị PartitionKey không được đặt, vì vậy theo mặc định giá trị PartitionKey là null, dẫn đến Object reference not set to an instance of an object.ngoại lệ

Kiểm tra xem bạn có đang cung cấp các giá trị thích hợp cho PartitionKey hoặc RowKey hay không, bạn có thể gặp phải vấn đề như vậy.


0

Tôi đã sửa các trường hợp của mình và nó hoạt động tốt

Trường hợp của tôi:

  1. Phím hàng không đúng định dạng (400).
  2. Sự kết hợp giữa phân vùng và phím hàng không phải là duy nhất (409).

0

Tôi nhận được 400 Yêu cầu không hợp lệ vì tôi đang sử dụng ZRS (Bộ nhớ dự phòng theo vùng) và Analytics không khả dụng cho loại bộ nhớ này. Tôi không biết mình đang sử dụng Analytics.

Tôi đã xóa vùng chứa lưu trữ và tạo lại dưới dạng GRS và bây giờ nó hoạt động tốt.


0

Tôi nhận được (400) Yêu cầu không hợp lệ, StatusMessage: Yêu cầu không hợp lệ, Mã lỗi: OutOfRangeInput khi đối tượng có thuộc tính DateTime không được đặt (= DateTime.MinValue)


0

Trong trường hợp của tôi: Tôi đã bao gồm siêu dữ liệu blob với tên thẻ chứa dấu gạch nối.

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

Dấu gạch ngang "added-by"là vấn đề và sau đó RTFM nói với tôi rằng các tên thẻ phải tuân theo các quy ước về mã định danh C #.

Tham khảo: https://docs.microsoft.com/en-us/azure/storage/blobs/storage-properties-metadata

Dấu gạch dưới hoạt động tốt.


0

Trong trường hợp của tôi, tôi không nên thêm PartitionKey và Rowkey vào lớp thực thể của mình. Nó phải là từ lớp cơ sở. Dưới đây sẽ chỉ hoạt động.

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


      public TableRunLogMessage() { }
}

0

Nếu bạn đang sử dụng NodeJS và tình cờ xem được bài đăng này, chỉ để thấy rằng bạn không nhận được thông tin chi tiết đáng yêu đó trong đối tượng lỗi của mình; bạn có thể sử dụng proxy để lấy những chi tiết đó. Tuy nhiên, vì không ai ở đây đề cập đến CÁCH sử dụng proxy.

Cách đơn giản nhất với NodeJS là thiết lập hai biến môi trường:

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.

Nếu bạn thực sự đang sử dụng C #, giống như tác giả của bài viết này đang làm; bạn có thể chỉ cần cài đặt Fiddler và đặt nó ở chế độ chặn. Theo mặc định, nó sẽ chặn các yêu cầu. Bạn cũng có thể cần phải tin tưởng chứng chỉ của Fiddler hoặc làm tương đương với "NODE_TLS_REJECT_UNAUTHORIZED = 0" của Node.


0

Tôi đã nhận được phản hồi 400-BadRequest từ API bảng tài khoản lưu trữ Azure. Thông tin ngoại lệ cho thấy rằng "Tài khoản đang được truy cập không hỗ trợ http.". Tôi nhận ra rằng chúng ta phải sử dụng https trong chuỗi kết nối khi "Yêu cầu chuyển an toàn" được bật trong cấu hình tài khoản lưu trữ như được hiển thị trong hình ảnh bên dưới.nhập mô tả hình ảnh ở đây


0

Trong trường hợp của tôi để tạo phiên bản mới của lớp "TableBotDataStore" (MS bot framework), chúng tôi truyền tham số "tableName" với dấu gạch ngang như "master-bot" và TableBotDataStore chỉ có thể có tên bảng với chữ và số.


0

Tôi đã gặp vấn đề tương tự, hàm đang truyền containerNameKeydưới dạng chuỗi. dưới đây là mã đã báo lỗi

container = blobClient.GetContainerReference(containerNameKey) 

Tôi đã đổi nó thành

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

Nó đã làm việc

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.