HttpClient 요청에 대해 Content-Type 헤더를 어떻게 설정합니까?


739

호출하는 API에 필요한 객체 Content-Type헤더 를 설정하려고합니다 HttpClient.

Content-Type아래와 같이 설정을 시도했습니다 .

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

Accept헤더 를 추가 할 수는 있지만 추가하려고 Content-Type하면 다음 예외가 발생합니다.

헤더 이름이 잘못되었습니다. 요청 헤더 HttpRequestMessage는와 함께 사용하고 응답 헤더는와 함께 사용 HttpResponseMessage하고 콘텐츠 헤더는 HttpContent객체 와 함께 사용해야 합니다.

요청 에서 Content-Type헤더를 어떻게 설정 HttpClient합니까?


.NET Core에서 HttpWebRequest가 수행하는 방식을 따를 수 있습니다 (내부적으로 HttpClient를 사용함). github.com/dotnet/corefx/blob/master/src/System.Net.Requests/… "SendRequest"메소드
jiping-s

답변:


928

컨텐츠 유형은 요청이 아닌 컨텐츠의 헤더이므로 이것이 실패하는 이유입니다. AddWithoutValidationRobert Levy가 제안한대로 작동 할 수도 있지만 요청 컨텐츠 자체를 작성할 때 컨텐츠 유형을 설정할 수도 있습니다 (코드 스 니펫은 Accept 및 Content-Type 헤더의 두 위치에 "application / json"을 추가 함).

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

32
또는 Response.Content.Headers대부분의 시간 동안 작동합니다.
존 Gietzen

4
@AshishJain Response.Content.HeadersASP.Net Web API 와 관련 하여 본 SO 답변의 대부분은 작동하지 않지만 HttpContext.Current.Response.ContentType필요한 경우 쉽게 사용할 수 있습니다 .
jerhewet

6
@ jerhewet 나는 나를 위해 일한 다음과 같은 방식으로 사용했습니다. var content = new StringContent (data, Encoding.UTF8, "application / json");
Ashish-BeJovial

22
Content-Type은 페이로드가있는 HTTP 메시지의 속성입니다. 요청 대 응답과 관련이 없습니다.
Julian Reschke

6
흥미 롭군 세 개의 매개 변수를 사용하여 새 StringContent를 만들려고 시도했지만 작동하지 않았습니다. 그런 다음 수동으로 request.Content.Headers.Remove ( "Content-Type") 다음 request.Content.Headers.Add ( "Content-Type", "application / query + json")하고 작동했습니다. 이상한.
Bill Noel

163

Johns가 carlos 솔루션에 대해 언급하지 않은 사람들을 위해 ...

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

PDF를 다운로드하는 데 차이가있었습니다. 전화에서 HTML을 다운로드하려고했습니다. 확장자를 변환 한 후 파일은 정상적으로 인코딩되었습니다.
Matteo Defanti

끝에 .ToString ()을 던져야했지만 WCF 서비스 구현에서 작동했습니다.
존 메이어

2
나는 시행 착오에 의해 "req"라는 객체 유형이 무엇인지 알아낼 것이다. 당신의 배려에 감사합니다.
granadaCoder

4
MediaTypeHeaderValue를 사용하면 캐릭터 셋을 설정하려고 할 때 오류를 반환합니다. response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/xml; charset=utf-8");
MBak

3
Johns는 Carlo의 솔루션에 대해 Response.Content.Headers를 언급했지만 req.Content.Headers? 즉 요청 대 응답?
joedotnot

52

작은 라이브러리 종속성을 신경 쓰지 않으면 Flurl.Http [공개 : 저자입니다]는이를 간단하게 만듭니다. 이 PostJsonAsync방법은 내용을 직렬화하고 content-type헤더를 설정 ReceiveJson하고 응답을 역 직렬화합니다. accept헤더가 필요한 경우 직접 설정해야하지만 Flurl 은이를 수행하는 매우 깨끗한 방법을 제공합니다.

using Flurl.Http;

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

Flurl은 HttpClient와 Json.NET을 사용하며 PCL이므로 다양한 플랫폼에서 작동합니다.

PM> Install-Package Flurl.Http

컨텐츠가 application / x-www-form-urlencoded 인 경우 어떻게 전송합니까?
Vlado Pandžić

2
사용했습니다. <1 분 안에 달성하는데 오랜 시간이 걸리던 일을 달성했습니다. 이 라이브러리를 무료로 유지해 주셔서 감사합니다.
Najeeb

35

TryAddWithoutValidation을 사용해보십시오

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

4
작동하지 않으면 '미사용 헤더 이름이 표시됩니다. 요청 헤더를 HttpRequestMessage와 함께 사용하고 응답 헤더를 HttpResponseMessage와 함께 사용하고 컨텐츠 헤더를 HttpContent 객체와 함께 사용해야합니다. '
Martin Lietz

3
"작업 중"또는 "작동하지 않음"을보고하는 사람들은 HttpClient가 요즘 매우 모호한 개체입니다. 전체 이름 (space)과 .dll 어셈블리를보고하십시오.
granadaCoder

Misused header name오류 DOTNET 코어 2.2 확인된다. @carlosfigueira의 답변 stackoverflow.com/a/10679340/2084315 을 사용해야했습니다 .
ps2goat

전체 .net 작품 (4.7)에서 작동합니다.
ZakiMa

28

닷넷은 즉 것으로, 특정 표준을 준수하도록 강요하려고 Content-Type헤더 만 콘텐츠를 요청 (예 지정할 수 있습니다 POST, PUT등). 따라서 다른 사람들이 지적 Content-Type했듯이 헤더 를 설정하는 바람직한 방법 은 HttpContent.Headers.ContentType속성을 통하는 것 입니다.

그렇게 말하면 특정 API (예 : 2016-12-19 현재 LiquidFiles Api ) Content-TypeGET요청에 대한 헤더를 설정해야합니다 . .Net은 요청 자체에서이 헤더를 설정하는 것을 허용하지 않습니다 TryAddWithoutValidation. 또한 Content길이가 0 인 경우에도 요청에 대해를 지정할 수 없습니다 . 내가이 문제를 해결할 수있는 유일한 방법은 반사에 의지하는 것입니다. 코드 (다른 사람이 필요로하는 경우)는

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

편집하다:

주석에서 언급했듯이이 필드는 dll 버전마다 이름이 다릅니다. GitHub소스 코드에서 필드의 이름은 현재 s_invalidHeaders입니다. @David Thompson의 제안에 따라이 예를 설명하도록 예제가 수정되었습니다.


1
이 필드는 이제 s_invalidHeaders이므로 다음을 사용하면 호환성이 보장됩니다. 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);
David Thompson

2
감사합니다 감사합니다! 때로는 Microsoft API에 실패했을 때 마운트가 멈추고 잠꼬대가 나옵니다. 매우 간단한 게시물을 본 후 정리할 수있었습니다. 아니 너무 나쁜 ..
제라드 오닐

1
이 코드가 설명하는 치명적인 오류를 발생시키는 방법에 대해 혼란스러워합니다. 사용 사례 및 수신중인 오류에 대한 자세한 정보를 제공 할 수 있습니까?
erdomke

2
와. Asp.net WebApi GET 메소드를 사용하려면 Content-Type을 명시 적으로 지정해야합니다. = (
AlfeG

2
홀리 몰리, 난 이것에 의지해야한다고 믿을 수 없어. .NET 프레임 워크 개발자는 언제 Http 헤더 섹션에 추가 할 수있는 것을 손에 쥐어 야합니까? 가증하다.
mmix

17

.NET Core에 대한 몇 가지 추가 정보 (콘텐츠가없는 요청에서 콘텐츠 유형을 제공하기 위해 개인 필드 설정에 대한 Erdomke의 게시물을 읽은 후) ...

내 코드를 디버깅 한 후 리플렉션을 통해 설정할 개인 필드를 볼 수 없으므로 문제를 재현하려고 생각했습니다.

.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;

그리고 예상대로 콘텐츠에 대한 총체 예외가 발생합니다. "Cannot send a content-body with this verb-type."

그러나 .NET Core (1.1)와 동일한 작업을 수행하면 예외가 발생하지 않습니다.내 서버 응용 프로그램에서 내 요청에 매우 만족스럽게 응답하고 내용 유형을 선택했습니다.

나는 그것에 대해 유쾌하게 놀랐으며, 누군가에게 도움이되기를 바랍니다!


1
고마워, Jay-코어를 사용하지 않고, 에르 돔케의 대답을 사용할 것이다. 모든 합리적인 길을 시도했다는 것을 알고 감사합니다 :).
제라드 오닐

1
.net 4가 작동하지 않습니다 ({ "이 동사 유형의 컨텐츠 본문을 보낼 수 없습니다."})
Tarek El-Mallah

3
@ TarekEl-Mallah 예-내 답변의 의견을 읽으십시오. 내 게시물의 요점은 .NET 4에서는 작동하지 않지만 .NET 코어에서는 작동한다는 것을 설명하는 것이 었습니다 (동일하지는 않습니다). .NET 4에서 작동하도록 OP를 해킹하려면 OP의 질문에 대한 erdomeke의 답변을 확인해야합니다.
Jay

16

AddWithoutValidation대신 호출 Add하십시오 ( 이 MSDN 링크 참조 ).

또는 사용중인 API가 POST 또는 PUT 요청 (일반적인 GET 요청이 아닌)에 대해서만 필요하다고 생각합니다. 이 경우을 호출 HttpClient.PostAsync하고 전달할 때 해당 객체 HttpContentHeaders속성 에서 설정하십시오 HttpContent.


작동하지 않으면 '미사용 헤더 이름이 표시됩니다. 요청 헤더는 HttpRequestMessage와 함께 사용하고 응답 헤더는 HttpResponseMessage와 함께 사용하고 컨텐츠 헤더는 HttpContent 객체와 함께 사용해야합니다. '
Martin Lietz

3
AddWithoutValidation이 존재하지 않음
KansaiRobot

14

문제가있는 사람들을 위해 charset

서비스 공급자가 문자 집합을 수락하지 않는 매우 특별한 경우가 있었으며 하위 구조를 변경하여 허용하지 않았습니다 ... 불행히도 HttpClient는 StringContent를 통해 자동으로 헤더를 설정하고 null 또는 Encoding.UTF8, 항상 문자셋을 설정합니다 ...

오늘 저는 서브 시스템을 바꾸려고 노력했습니다. HttpClient에서 다른 것으로 이동하여 무언가가 떠 올랐습니다. 반사를 사용하여 "문자 세트"를 비우는 것은 어떻습니까? ... 그리고 그것을 시도하기 전에, 나는 "초기화 후에 그것을 바꿀 수 있을지도 모른다"고 생각했습니다.

"; charset = utf-8"없이 정확한 "application / json"헤더를 설정하는 방법은 다음과 같습니다.

var jsonRequest = JsonSerializeObject(req, options); // Custom function that parse object to string
var stringContent = new StringContent(jsonRequest, Encoding.UTF8, "application/json");
stringContent.Headers.ContentType.CharSet = null;
return stringContent;

참고 :null 다음 의 값은 작동하지 않으며 "; charset = utf-8"

return new StringContent(jsonRequest, null, "application/json");

편집하다

@DesertFoxAZ는 다음 코드도 사용할 수 있으며 정상적으로 작동한다고 제안합니다. (직접 테스트하지 않았습니다)

stringContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");

1
stringContent.Headers.ContentType = 새로운 MediaTypeHeaderValue ( "application / json"); 또한 작동
DesertFoxAZ

4
var content = new JsonContent();
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
content.Headers.ContentType.Parameters.Add(new NameValueHeaderValue("charset", "utf-8"));
content.Headers.ContentType.Parameters.Add(new NameValueHeaderValue("IEEE754Compatible", "true"));

필요한 모든 것입니다.

Newtonsoft.Json을 사용하면 json 문자열로 컨텐츠가 필요합니다.

public class JsonContent : HttpContent
   {
    private readonly MemoryStream _stream = new MemoryStream();
    ~JsonContent()
    {
        _stream.Dispose();
    }

    public JsonContent(object value)
    {
        Headers.ContentType = new MediaTypeHeaderValue("application/json");
        using (var contexStream = new MemoryStream())
        using (var jw = new JsonTextWriter(new StreamWriter(contexStream)) { Formatting = Formatting.Indented })
        {
            var serializer = new JsonSerializer();
            serializer.Serialize(jw, value);
            jw.Flush();
            contexStream.Position = 0;
            contexStream.WriteTo(_stream);
        }
        _stream.Position = 0;

    }

    private JsonContent(string content)
    {
        Headers.ContentType = new MediaTypeHeaderValue("application/json");
        using (var contexStream = new MemoryStream())
        using (var sw = new StreamWriter(contexStream))
        {
            sw.Write(content);
            sw.Flush();
            contexStream.Position = 0;
            contexStream.WriteTo(_stream);
        }
        _stream.Position = 0;
    }

    protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
    {
        return _stream.CopyToAsync(stream);
    }

    protected override bool TryComputeLength(out long length)
    {
        length = _stream.Length;
        return true;
    }

    public static HttpContent FromFile(string filepath)
    {
        var content = File.ReadAllText(filepath);
        return new JsonContent(content);
    }
    public string ToJsonString()
    {
        return Encoding.ASCII.GetString(_stream.GetBuffer(), 0, _stream.GetBuffer().Length).Trim();
    }
}

1
그것이 무엇을하는지 작은 설명을 해 줄 수 있습니까?
Alejandro

2
첫 번째 줄은 CS0144와 함께 실패합니다 "추상 클래스 또는 인터페이스 'HttpContent'의 인스턴스를 만들 수 없습니다"
랜달 플래그를

1
그리고HttpMessageHandler handler = new WebRequestHandler(); HttpResponseMessage result; using (var client = (new HttpClient(handler, true))) { result = client.PostAsync(fullUri, content).Result; }
art24war

2

좋아, HTTPClient는 아니지만 사용할 수 있다면 WebClient는 매우 쉽습니다.

using (var client = new System.Net.WebClient())
 {
    client.Headers.Add("Accept", "application/json");
    client.Headers.Add("Content-Type", "application/json; charset=utf-8");
    client.DownloadString(...);
 }

1

당신은 이것을 사용할 수 있습니다!

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

HttpResponseMessage response = await _httpClient.SendAsync(msg);
response.EnsureSuccessStatusCode();

string json = await response.Content.ReadAsStringAsync();

0

다음과 같은 방법으로 가장 간단하고 이해하기 쉽습니다.

async Task SendPostRequest()
{
    HttpClient client = new HttpClient();
    var requestContent = new StringContent(<content>);
    requestContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
    var response = await client.PostAsync(<url>, requestContent);
    var responseString = await response.Content.ReadAsStringAsync();
}
...

SendPostRequest().Wait();

0

다음과 같이해야합니다.

    HttpContent httpContent = new StringContent(@"{ the json string }");
    httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));                
    HttpResponseMessage message = client.PostAsync(@"{url}", httpContent).Result;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.