2012-05-21 71 views
414

Tôi đang cố gắng đặt tiêu đề Content-Type của đối tượng HttpClient theo yêu cầu của API mà tôi đang gọi.Làm cách nào để bạn đặt tiêu đề Kiểu nội dung cho yêu cầu HttpClient?

tôi đã cố gắng thiết lập các Content-Type như dưới đây:

using (var httpClient = new HttpClient()) 
{ 
    httpClient.BaseAddress = new Uri("http://example.com/"); 
    httpClient.DefaultRequestHeaders.Add("Accept", "application/json"); 
    httpClient.DefaultRequestHeaders.Add("Content-Type", "application/json"); 
    // ... 
} 

Nó cho phép tôi để thêm Accept tiêu đề nhưng khi tôi cố gắng thêm Content-Type nó ném ngoại lệ sau đây:

lạm dụng tên tiêu đề. Đảm bảo tiêu đề yêu cầu được sử dụng với HttpRequestMessage, tiêu đề phản hồi với HttpResponseMessage và tiêu đề nội dung có các đối tượng HttpContent.

Làm cách nào để đặt tiêu đề Content-Type trong yêu cầu HttpClient?

Trả lời

513

Loại nội dung là tiêu đề nội dung chứ không phải yêu cầu, đó là lý do tại sao điều này không thành công. AddWithoutValidation theo đề xuất của Robert Levy có thể hoạt động, nhưng bạn cũng có thể đặt loại nội dung khi tạo nội dung yêu cầu (lưu ý rằng đoạn mã thêm "application/json" vào hai vị trí cho tiêu đề Accept và Content-Type):

HttpClient client = new HttpClient(); 
client.BaseAddress = new Uri("http://example.com/"); 
client.DefaultRequestHeaders 
     .Accept 
     .Add(new MediaTypeWithQualityHeaderValue("application/json"));//ACCEPT header 

HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "relativeAddress"); 
request.Content = new StringContent("{\"name\":\"John Doe\",\"age\":33}", 
            Encoding.UTF8, 
            "application/json");//CONTENT-TYPE header 

client.SendAsync(request) 
     .ContinueWith(responseTask => 
     { 
      Console.WriteLine("Response: {0}", responseTask.Result); 
     }); 
+18

Ngoài ra, 'Response.Content.Headers' sẽ hoạt động hầu hết thời gian. –

+2

@AshishJain Hầu hết các câu trả lời SO tôi đã thấy liên quan đến 'Response.Content.Headers' cho API Web ASP.Net chưa hoạt động, nhưng bạn có thể dễ dàng đặt nó bằng cách sử dụng' HttpContext.Current.Response.ContentType' nếu bạn cần phải. – jerhewet

+4

@jerhewet i được sử dụng theo cách làm việc cho tôi. var content = new StringContent (dữ liệu, Encoding.UTF8, "application/json"); –

14

Gọi AddWithoutValidation thay vì Add (xem this MSDN link).

Hoặc, tôi đoán API bạn đang sử dụng thực sự chỉ yêu cầu điều này cho các yêu cầu POST hoặc PUT (không phải yêu cầu GET thông thường). Trong trường hợp đó, khi bạn gọi HttpClient.PostAsync và chuyển vào một số HttpContent, hãy đặt số này trên thuộc tính Headers của đối tượng HttpContent đó.

+1

AddWithoutValidation ném cùng một lỗi – mynameiscoffey

+0

không hoạt động .... –

+0

không hoạt động mang lại cho tôi 'Tên tiêu đề bị lạm dụng. Đảm bảo tiêu đề yêu cầu được sử dụng với HttpRequestMessage, tiêu đề phản hồi với HttpResponseMessage và tiêu đề nội dung có các đối tượng HttpContent. ' –

91

Đối với những người không thấy Johns bình luận cho giải pháp carlos ...

req.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); 
+0

Nó tạo sự khác biệt khi tải xuống bản pdf. Từ điện thoại, nó đã cố gắng tải xuống một HTML. Sau khi chuyển đổi phần mở rộng, tập tin thường được mã hóa. –

+0

Tôi phải ném.ToString() vào cuối, nhưng có điều này làm việc cho một thực hiện dịch vụ WCF. –

33

Nếu bạn không nhớ một sự phụ thuộc thư viện nhỏ, Flurl.Http [tiết lộ: tôi là tác giả] làm này uber-đơn giản. Phương thức PostJsonAsync của chúng tôi đảm nhiệm cả việc sắp xếp thứ tự nội dung và đặt tiêu đề content-typeReceiveJson deserializes phản hồi. Nếu accept tiêu đề là cần thiết bạn sẽ cần phải thiết lập rằng chính mình, nhưng Flurl cung cấp một cách khá sạch để làm điều đó quá:

using Flurl.Http; 

var result = await "http://example.com/" 
    .WithHeader("Accept", "application/json") 
    .PostJsonAsync(new { ... }) 
    .ReceiveJson<TResult>(); 

Flurl sử dụng HttpClient và Json.NET dưới mui xe, và đó là một PCL nên nó sẽ hoạt động trên nhiều nền tảng khác nhau.

PM> Install-Package Flurl.Http 
+0

Cách gửi nếu nội dung là ứng dụng/x-www-form-urlencoded? –

+0

@Vlado sử dụng 'PostUrlEncodedAsync'. http://tmenier.github.io/Flurl/fluent-http/ –

21

cố gắng sử dụng TryAddWithoutValidation

var client = new HttpClient(); 
    client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json; charset=utf-8"); 
+9

không hoạt động .... –

+0

không hoạt động mang lại cho tôi 'Tên tiêu đề bị lạm dụng. Đảm bảo tiêu đề yêu cầu được sử dụng với HttpRequestMessage, tiêu đề phản hồi với HttpResponseMessage và tiêu đề nội dung có các đối tượng HttpContent. ' –

11

Net cố gắng để buộc bạn phải tuân theo các tiêu chuẩn nhất định, cụ thể là tiêu đề Content-Type chỉ có thể được xác định trên yêu cầu có nội dung (ví dụ POST, PUT , v.v.) Vì vậy, như những người khác đã chỉ ra, cách ưa thích để đặt tiêu đề Content-Type là thông qua thuộc tính HttpContent.Headers.ContentType.

Với điều đó đã nói, một số API nhất định (chẳng hạn như LiquidFiles Api, kể từ 2016-12-19) yêu cầu đặt tiêu đề Content-Type cho yêu cầu GET. .Net sẽ không cho phép đặt tiêu đề này theo yêu cầu - thậm chí sử dụng TryAddWithoutValidation. Ngoài ra, bạn không thể chỉ định một yêu cầu Content cho yêu cầu - ngay cả khi nó có độ dài bằng 0. Cách duy nhất tôi có thể dường như để có được xung quanh này là để nghỉ mát để phản ánh. Mã (trong trường hợp một số khác cần nó) là

var field = typeof(System.Net.Http.Headers.HttpRequestHeaders) 
    .GetField("invalidHeaders", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static) 
    ?? typeof(System.Net.Http.Headers.HttpRequestHeaders) 
    .GetField("s_invalidHeaders", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); 
if (field != null) 
{ 
    var invalidFields = (HashSet<string>)field.GetValue(null); 
    invalidFields.Remove("Content-Type"); 
} 
_client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "text/xml"); 

Edit:

Như đã đề cập trong các ý kiến, lĩnh vực này có tên gọi khác nhau trong các phiên bản khác nhau của dll. Trong số source code on GitHub, trường hiện được đặt tên là s_invalidHeaders. Ví dụ này đã được sửa đổi để tính đến điều này theo đề xuất của @David Thompson.

+0

Không hoạt động với .Net Framework phiên bản 4.0, System.Net.Http phiên bản 2.2.29.0 nhưng hoạt động với 2.0.0.0 – prem

+0

Trường này hiện là s_invalidHeaders để sử dụng như sau đảm bảo khả năng tương thích: var field = typeof (System.Net.Http .Headers.HttpRequestHeaders) .GetField ("invalidHeaders", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static) ?? typeof (System.Net.Http.Headers.HttpRequestHeaders) .GetField ("s_invalidHeaders", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static); –

+0

Đã thêm một câu trả lời liên quan đến điều này cho .NET Core 1.1 – Jay

9

Một số thông tin thêm về NET Core (sau khi đọc bài erdomke về thiết lập một lĩnh vực tư nhân để cung cấp content-type trên một yêu cầu mà không có nội dung) ...

Sau khi gỡ lỗi mã của tôi, tôi không thể nhìn thấy trường riêng tư để đặt qua phản xạ - vì vậy tôi nghĩ tôi sẽ cố gắng tạo lại sự cố.

Tôi đã thử đoạn mã sau sử dụng Net 4.6:

HttpRequestMessage httpRequest = new HttpRequestMessage(HttpMethod.Get, @"myUrl"); 
httpRequest.Content = new StringContent(string.Empty, Encoding.UTF8, "application/json"); 

HttpClient client = new HttpClient(); 
Task<HttpResponseMessage> response = client.SendAsync(httpRequest); //I know I should have used async/await here! 
var result = response.Result; 

Và, như mong đợi, tôi nhận được một ngoại lệ tổng hợp với nội dung "Cannot send a content-body with this verb-type."

Tuy nhiên, nếu tôi làm điều tương tự với. NET Core (1.1) - Tôi không nhận được ngoại lệ. Yêu cầu của tôi đã được ứng dụng máy chủ của tôi khá vui vẻ trả lời và loại nội dung đã được chọn.

Tôi đã rất ngạc nhiên về điều đó và tôi hy vọng nó sẽ giúp một ai đó!

+1

Cảm ơn, Jay - Không sử dụng cốt lõi, và sẽ sử dụng câu trả lời của erdomke. Tôi đánh giá cao khi biết rằng tất cả các con đường hợp lý đã được thử :). –

+0

hoạt động tốt trong .NET Core thực sự, cảm ơn! –

+0

không hoạt động .net 4 ({"Không thể gửi nội dung có động từ này."}) –

Các vấn đề liên quan