2012-05-21 10 views
414

Sto tentando di impostare l'intestazione Content-Type di un oggetto HttpClient come richiesto da un'API che sto chiamando.Come si imposta l'intestazione Content-Type per una richiesta HttpClient?

ho provato a fissare il Content-Type come di seguito:

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"); 
    // ... 
} 

Mi permette di aggiungere l'intestazione Accept ma quando provo ad aggiungere Content-Type getta la seguente eccezione:

abusato nome dell'intestazione. Assicurarsi che le intestazioni di richiesta vengano utilizzate con HttpRequestMessage, le intestazioni di risposta con le intestazioni di contenuto HttpResponseMessage e con gli oggetti HttpContent.

Come posso impostare il Content-Type intestazione in una richiesta HttpClient?

risposta

513

Il tipo di contenuto è un'intestazione del contenuto, non della richiesta, motivo per cui questo non funziona. AddWithoutValidation come suggerito da Robert Levy potrebbe funzionare, ma è anche possibile impostare il tipo di contenuto quando si crea il contenuto della richiesta stessa (si noti che lo snippet di codice aggiunge "application/json" in due punti, per le intestazioni Accept e 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

In alternativa, 'Response.Content.Headers' funzionerà la maggior parte del tempo. –

+2

@AshishJain La maggior parte delle risposte SO che ho visto coinvolgere 'Response.Content.Headers' per l'API Web ASP.Net non ha funzionato, ma è possibile impostarlo facilmente usando' HttpContext.Current.Response.ContentType' if devi. – jerhewet

+4

@jerhewet ho usato nel modo seguente che ha funzionato per me. var content = new StringContent (data, Encoding.UTF8, "application/json"); –

14

Chiama AddWithoutValidation anziché Add (vedere this MSDN link).

In alternativa, suppongo che l'API che si sta utilizzando richieda solo questo per le richieste POST o PUT (non per le richieste GET ordinarie). In tal caso, quando si chiama HttpClient.PostAsync e si passa in un HttpContent, impostarlo sulla proprietà dell'oggetto HttpContent.

+1

AddWithoutValidation genera lo stesso errore – mynameiscoffey

+0

non funzionante .... –

+0

non funzionante mi restituisce un 'intestazione di nome errato. Assicurati che le intestazioni di richiesta vengano utilizzate con HttpRequestMessage, le intestazioni di risposta con HttpResponseMessage e le intestazioni di contenuto con oggetti HttpContent. " –

91

per coloro che non ha visto Johns commento alla soluzione carlos ...

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

Ha fatto la differenza scaricando un pdf. Dal telefono ha provato a scaricare un HTML. Dopo aver convertito l'estensione, il file era normalmente codificato. –

+0

Ho dovuto buttare.ToString() alla fine, ma sì, questo ha funzionato per un'implementazione del servizio WCF. –

33

Se non ti dispiace una piccola dipendenza biblioteca, Flurl.Http [divulgazione: sono l'autore] rende questo uber-semplice. Il suo metodo PostJsonAsync si occupa sia della serializzazione del contenuto che dell'impostazione dell'intestazione content-type, mentre il numero ReceiveJson deserializza la risposta. Se è necessaria l'intestazione accept è necessario impostare che da soli, ma Flurl fornisce un modo abbastanza pulito per fare anche questo:

using Flurl.Http; 

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

Flurl utilizza HttpClient e Json.NET sotto il cofano, ed è un modo PCL funzionerà su una varietà di piattaforme.

PM> Install-Package Flurl.Http 
+0

Come inviare se il contenuto è application/x-www-form-urlencoded? –

+0

@Vlado usa 'PostUrlEncodedAsync'. http://tmenier.github.io/Flurl/fluent-http/ –

21

tenta di utilizzare TryAddWithoutValidation

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

non funziona .... –

+0

non funziona mi dà un 'nome di intestazione misused. Assicurati che le intestazioni di richiesta vengano utilizzate con HttpRequestMessage, le intestazioni di risposta con HttpResponseMessage e le intestazioni di contenuto con oggetti HttpContent. " –

11

.Net cerca di costringere a obbedire a determinati standard, vale a dire che l'intestazione Content-Type può essere specificato solo sulle richieste che hanno contenuti (ad esempio POST, PUT , eccetera.). Pertanto, come altri hanno indicato, il modo preferito per impostare l'intestazione Content-Type tramite la proprietà HttpContent.Headers.ContentType.

Detto questo, alcune API (come ad esempio LiquidFiles Api, a partire dal 2016-12-19) richiedono l'impostazione dell'intestazione Content-Type per una richiesta GET. .Net non consentirà di impostare questa intestazione sulla richiesta stessa - anche usando TryAddWithoutValidation. Inoltre, non è possibile specificare un Content per la richiesta, anche se è di lunghezza zero. L'unico modo in cui potevo aggirare questo era ricorrere alla riflessione. Il codice (nel caso in cui qualche altro ne ha bisogno) è

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:

Come notato nei commenti, questo campo ha nomi diversi in diverse versioni della DLL. Nel source code on GitHub, il campo è attualmente denominato s_invalidHeaders. L'esempio è stato modificato per tener conto di ciò secondo il suggerimento di @David Thompson.

+0

Non funziona con .Net Framework versione 4.0, System.Net.Http versione 2.2.29.0 ma funziona con 2.0.0.0 – prem

+0

Questo campo è ora s_invalidHeaders, quindi l'utilizzo di quanto segue garantisce la compatibilità: 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

Aggiunto una risposta relativa a questo per .NET Core 1.1 – Jay

9

Alcuni informazioni supplementari su .NET core (dopo aver letto il post di erdomke sull'impostazione di un campo privato per fornire il tipo di contenuto su una richiesta che non ha contenuto) ...

dopo il debug il mio codice, ho non riesco a vedere il campo privato da impostare tramite riflessione - quindi ho pensato di provare a ricreare il problema.

Ho provato il seguente codice utilizzando .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; 

E, come previsto, ottengo un'eccezione di aggregazione con il contenuto "Cannot send a content-body with this verb-type."

Tuttavia, se faccio la stessa cosa con. NET Core (1.1) - Non ottengo un'eccezione. La mia richiesta è stata soddisfacentemente soddisfatta dalla mia applicazione server e il tipo di contenuto è stato prelevato.

Sono rimasto piacevolmente sorpreso da questo, e spero che aiuti qualcuno!

+1

Grazie, Jay: non si utilizza il core e utilizzerà la risposta di erdomke. Apprezzo sapere che tutte le vie ragionevoli sono state provate :). –

+0

funziona perfettamente con .NET Core, grazie! –

+0

non funziona .net 4 ({"Impossibile inviare un corpo del contenuto con questo tipo di verbo."}) –

Problemi correlati