System.Net.WebRequest를 사용할 때 일부 HTTP 헤더를 설정할 수 없습니다


130

WebRequest객체 에 HTTP 헤더 키 / 값 쌍을 추가하려고 하면 다음 예외가 발생합니다.

이 헤더는 적절한 속성을 사용하여 수정해야합니다

HeadersAdd () 메서드를 사용하여 컬렉션에 새 값을 추가하려고 시도 했지만 여전히 동일한 예외가 발생합니다.

webRequest.Headers.Add(HttpRequestHeader.Referer, "http://stackoverflow.com");

WebRequest 객체를 HttpWebRequest로 캐스팅하고과 같은 속성을 설정 하여이 문제를 해결할 수 httpWebReq.Referer ="http://stackoverflow.com"있지만 속성을 통해 노출되는 소수의 헤더에서만 작동합니다.

원격 리소스에 대한 요청으로 헤더 수정을보다 세밀하게 제어 할 수있는 방법이 있는지 알고 싶습니다.

답변:


182

짧은 기술 답변이 필요한 경우 답변의 마지막 섹션으로 바로 이동하십시오.

더 잘 알고 싶다면 모두 읽으십시오.


나는 오늘도이 문제에 대응했으며 오늘 내가 발견 한 것은 다음과 같습니다.

  1. 위의 답변은 다음과 같습니다.

    1.1 추가하려는 헤더가 이미 존재한다는 것을 알려주므로 다시 추가하지 않고 적절한 속성 (예 : 인덱서)을 사용하여 값을 수정해야합니다.

    1.2의 헤더를 변경할 때마다 HttpWebRequest객체 자체에 적절한 속성을 사용해야합니다 (있는 경우).

주요 지침에 대해 FOR와 Jvenema에게 감사드립니다 ...

  1. 그러나 내가 찾은 것은 퍼즐에서 누락 된 부분 입니다.

    2.1 WebHeaderCollection클래스는 일반적으로 WebRequest.Headers 또는 WebResponse.Headers를 통해 액세스합니다 . 일부 공통 헤더는 제한적인 것으로 간주되며 API (예 : Content-Type)에 의해 직접 노출되거나 시스템에 의해 보호되며 변경할 수 없습니다.

제한된 헤더는 다음과 같습니다.

  • Accept
  • Connection
  • Content-Length
  • Content-Type
  • Date
  • Expect
  • Host
  • If-Modified-Since
  • Range
  • Referer
  • Transfer-Encoding
  • User-Agent
  • Proxy-Connection

따라서 다음에이 예외에 직면 할 때이 문제를 해결하는 방법을 모를 경우 제한된 헤더가 있음을 기억하십시오. 해결책은 WebRequest/ HttpWebRequest클래스 에서 명시 적으로 적절한 속성을 사용하여 값을 수정하는 것 입니다.


편집 : (유용한 의견, 사용자 Kaido의 의견 )

해결 방법은 WebHeaderCollection.IsRestricted(key)add를 호출하기 전에 헤더가 이미 존재하는지 또는 제한되어 있는지 확인하는 것입니다 ( ).


8
"적절한 속성을 사용하여 값을 수정하십시오"
CRice

76
이 답변은 문제에 대한 해결책을 제시하지 않고 예외 메시지를 반복하는 것입니다.
000

11
해결책은 add를 호출하기 전에 헤더가 이미 존재하는지 또는 제한 된지 (WebHeaderCollection.IsRestricted (key)) 확인하는 것입니다.
Kaido

7
@Sam 섹션 1.1을 읽고 문제를 해결하십시오. 즉, via를 통해 추가하려는 속성이 Headers.Add()이미 존재하므로 대신 수정해야합니다.
Junaid Qadir

4
"이 제한이 .NET Framework의 기능이라는 점을 지적하는 것이 중요하다고 생각합니다."-이런 종류의 기능은 갖고 있지 않습니다.
Herberth Amaral

76

사용자 정의 웹 클라이언트 에서이 문제가 발생했습니다. 여러 가지 방법으로 사람들이 혼란 스러울 수 있다고 생각합니다. 사용하는 경우 WebRequest.Create()당신은 캐스팅 할 수 있습니다 HttpWebRequest추가하거나 헤더를 수정하는 속성을 사용합니다. 를 WebHeaderCollection사용할 때을 사용할 수 있습니다 .Add("referer","my_url").

예 1

WebClient client = new WebClient();
client.Headers.Add("referer", "http://stackoverflow.com");
client.Headers.Add("user-agent", "Mozilla/5.0");

예 2

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Referer = "http://stackoverflow.com";
request.UserAgent = "Mozilla/5.0";
response = (HttpWebResponse)request.GetResponse();

1
Ex 1 은이 예외로 내 문제를 해결했습니다. 그래서 client.Headers [ "referer"] = url을 변경했습니다. client.Headers.Add ( "referer", url); 일이 시작됩니다. 감사.
000

2
이 답변에는 데스크탑 .Net 런타임에서 작업하고 http를 요구한다는 가정이 포함되어 있습니다. WebRequest.Create는 사용하는 프로토콜 접두사에 따라 다양한 객체를 반환 할 수 있습니다. 누구나 관심이 있다면 CustomProtocolHandlers와 관련이 있습니다. 그리고 WP7 또는 Silverlight에서는 요청 구현 클래스도 약간 다릅니다. 이것에 조심하십시오.
quetzalcoatl

1
그러나 "Accept"헤더를 수정할 수 없습니다. 이것을 어떻게 수정할 수 있습니까?
사용자

첫 번째 예는 여전히 같은 오류를
나타냅니다

29

이전의 모든 답변은 솔루션을 제공하지 않고 문제를 설명합니다. 다음은 문자열 이름을 통해 헤더를 설정할 수있게하여 문제를 해결하는 확장 방법입니다.

용법

HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.SetRawHeader("content-type", "application/json");

확장 클래스

public static class HttpWebRequestExtensions
{
    static string[] RestrictedHeaders = new string[] {
            "Accept",
            "Connection",
            "Content-Length",
            "Content-Type",
            "Date",
            "Expect",
            "Host",
            "If-Modified-Since",
            "Keep-Alive",
            "Proxy-Connection",
            "Range",
            "Referer",
            "Transfer-Encoding",
            "User-Agent"
    };

    static Dictionary<string, PropertyInfo> HeaderProperties = new Dictionary<string, PropertyInfo>(StringComparer.OrdinalIgnoreCase);

    static HttpWebRequestExtensions()
    {
        Type type = typeof(HttpWebRequest);
        foreach (string header in RestrictedHeaders)
        {
            string propertyName = header.Replace("-", "");
            PropertyInfo headerProperty = type.GetProperty(propertyName);
            HeaderProperties[header] = headerProperty;
        }
    }

    public static void SetRawHeader(this HttpWebRequest request, string name, string value)
    {
        if (HeaderProperties.ContainsKey(name))
        {
            PropertyInfo property = HeaderProperties[name];
            if (property.PropertyType == typeof(DateTime))
                property.SetValue(request, DateTime.Parse(value), null);
            else if (property.PropertyType == typeof(bool))
                property.SetValue(request, Boolean.Parse(value), null);
            else if (property.PropertyType == typeof(long))
                property.SetValue(request, Int64.Parse(value), null);
            else
                property.SetValue(request, value, null);
        }
        else
        {
            request.Headers[name] = value;
        }
    }
}

시나리오

래퍼를 작성했으며 래퍼의 HttpWebRequest속성으로 13 개의 제한된 헤더를 모두 노출하고 싶지 않았습니다. 대신 나는 간단한을 사용하고 싶었다 Dictionary<string, string>.

또 다른 예는 요청에서 헤더를 가져 와서 수신자에게 전달해야하는 HTTP 프록시입니다.

실용적이지 않거나 속성을 사용할 수없는 다른 시나리오가 많이 있습니다. 사용자가 속성을 통해 헤더를 설정하도록하는 것은 매우 융통성이없는 디자인이므로 리플렉션이 필요합니다. 단점은 반사가 추상화되어 여전히 빠르며 (테스트에서 .001 초) 확장 방법이 자연 스럽습니다.

노트

RFC, http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2에 따라 헤더 이름은 대소 문자를 구분하지 않습니다 .


프록시 연결에 사용하지만 예, "프록시 연결"에 대한 키를 포함하면 null을 반환하므로 null 참조 예외가 발생합니다
deadManN

영리한 수정에 감사드립니다. 확장 프로그램에서 모든 헤더를 설정하도록했습니다.static Dictionary<string, PropertyInfo> HeaderProperties = new Dictionary<string, PropertyInfo>(StringComparer.InvariantCultureIgnoreCase); static WebRequestExtensions() { // Get property info for restricted headers. Type type = typeof(HttpWebRequest); foreach (string header in Enum.GetNames(typeof(HttpRequestHeader))) { var property = type.GetProperty(header.ToString()); if (property != null) { HeaderProperties.Add(property.Name, property); } } }
Suncat2000

13

내 코드가 "Accept"헤더 값을 다음과 같이 설정하려고 할 때 동일한 예외가 발생했습니다.

WebRequest request = WebRequest.Create("http://someServer:6405/biprws/logon/long");
request.Headers.Add("Accept", "application/json");

해결책은 이것을 다음과 같이 변경하는 것이 었습니다.

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://someServer:6405/biprws/logon/long");
request.Accept = "application/json";

12

의 헤더를 변경할 때마다 HttpWebRequest객체 자체에 적절한 속성을 사용해야합니다 (있는 경우). 플레인 WebRequest이 있으면 HttpWebRequest처음 으로 캐스팅하십시오 . 그런 다음 Referrer을 통해 액세스 할 수 있으므로 ((HttpWebRequest)request).Referrer헤더를 직접 수정할 필요가 없습니다. 속성을 올바른 값으로 설정하십시오. ContentLength, ContentType, UserAgent, 등, 모든 필요는이 방법을 설정합니다.

IMHO, 이것은 MS 부분의 단점입니다 ... 헤더를 통해 헤더를 설정 Headers.Add()하면 장면 뒤의 적절한 속성을 자동으로 호출해야합니다.


7

WebRequest 는 추상적이며 상속되는 클래스는 Headers 속성을 재정의해야하므로 .. 어떤 구체적인 WebRequest를 사용하고 있습니까? 즉, WebRequest 객체를 어떻게 사용할 수 있습니까?

ehr .. mnour 응답으로 인해 오류 메시지가 실제로 발견되었음을 알 수 있습니다. 추가하려는 헤더가 이미 존재하고 적절한 속성 (예 : 인덱서)을 사용하여 값을 수정해야한다는 것을 알려줍니다 )를 다시 추가하는 대신 아마 당신이 찾고 있던 전부일 것입니다.

WebRequest에서 상속되는 다른 클래스는 특정 헤더를 래핑하는 더 나은 속성을 가질 수 있습니다. 예를 들어이 게시물 을 참조하십시오 .


실제로 WebRequest.Create (url)은 WebRequest 객체의 인스턴스를 만듭니다.
Igal Tabachnik

2

위의 답변은 모두 훌륭하지만 문제의 본질은 일부 헤더가 한 방향으로 설정되고 다른 헤더는 다른 방식으로 설정된다는 것입니다. '제한된 헤더'목록은 위를 참조하십시오. 이를 위해 속성으로 설정하면됩니다. 다른 사람들에게는 실제로 헤더를 추가합니다. 여기를 보아라.

    request.ContentType = "application/x-www-form-urlencoded";

    request.Accept = "application/json";

    request.Headers.Add(HttpRequestHeader.Authorization, "Basic " + info.clientId + ":" + info.clientSecret);

1

기본적으로 그것은 http 헤더이므로 (질문에 표시된대로) 캐스트 HttpWebRequest하고 설정하는 것이 합리적입니다 .Referer.

HttpWebRequest req = ...
req.Referer = "your url";

1

참고 :이 솔루션은 WebClientSocket뿐만 아니라 HttpWebRequest 또는 WebHeaderCollection을 사용하여 헤더로 작업하는 다른 클래스에서도 작동합니다.

WebHeaderCollection.cs의 소스 코드를 보면 Hinfo를 사용하여 알려진 모든 헤더 정보를 유지할 수 있습니다.

private static readonly HeaderInfoTable HInfo = new HeaderInfoTable();

HeaderInfoTable 클래스를 보면 모든 데이터가 해시 테이블에 저장되어 있음을 알 수 있습니다.

private static Hashtable HeaderHashTable;

또한 HeaderInfoTable의 정적 생성자에서 모든 알려진 헤더가 HeaderInfo 배열에 추가 된 다음 해시 테이블에 복사되는 것을 볼 수 있습니다.

HeaderInfo 클래스를 마지막으로 보면 필드 이름이 표시됩니다.

internal class HeaderInfo {

    internal readonly bool IsRequestRestricted;
    internal readonly bool IsResponseRestricted;
    internal readonly HeaderParser Parser;

    //
    // Note that the HeaderName field is not always valid, and should not
    // be used after initialization. In particular, the HeaderInfo returned
    // for an unknown header will not have the correct header name.
    //

    internal readonly string HeaderName;
    internal readonly bool AllowMultiValues;
    ...
    }

따라서 위의 모든 내용을 반영하면 HeaderInfoTable 클래스에서 리플렉션을 사용하여 정적 Hashtable을 찾은 다음 해시 테이블 내의 모든 요청 제한 HeaderInfo를 무제한으로 변경하는 코드가 있습니다.

        // use reflection to remove IsRequestRestricted from headerInfo hash table
        Assembly a = typeof(HttpWebRequest).Assembly;
        foreach (FieldInfo f in a.GetType("System.Net.HeaderInfoTable").GetFields(BindingFlags.NonPublic | BindingFlags.Static))
        {
            if (f.Name == "HeaderHashTable")
            {
                Hashtable hashTable = f.GetValue(null) as Hashtable;
                foreach (string sKey in hashTable.Keys)
                {

                    object headerInfo = hashTable[sKey];
                    //Console.WriteLine(String.Format("{0}: {1}", sKey, hashTable[sKey]));
                    foreach (FieldInfo g in a.GetType("System.Net.HeaderInfo").GetFields(BindingFlags.NonPublic | BindingFlags.Instance))
                    {

                        if (g.Name == "IsRequestRestricted")
                        {
                            bool b = (bool)g.GetValue(headerInfo);
                            if (b)
                            {
                                g.SetValue(headerInfo, false);
                                Console.WriteLine(sKey + "." + g.Name + " changed to false");
                            }

                        }
                    }

                }
            }
        } 

훌륭한! : 웹 소켓을 설정함으로써이 문제를 해결 작업 할 때이 또한 가능 사용 요청에 대한 그 헤더를 설정할 수 있습니다 github.com/dotnet/corefx/issues/26627을
Øystein Kolsrud

모두 WebHeaderCollection을 사용하여 헤더를 조작하기 때문입니다. HttpWebRequest에서만 테스트했습니다.
슬리퍼 19.


0

아래에 표시된 HttpWebRequest로 WebRequest를 캐스트 할 수 있습니다.

var request = (HttpWebRequest)WebRequest.Create(myUri);

그런 다음 헤더 목록을 조작하는 대신 요청 속성 요청에 직접 적용하십시오.

request.Referer = "yourReferer";

이러한 특성은 요청 오브젝트에서 사용 가능합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.