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を読みました。つまり、追加しようとしているプロパティはHeaders.Add()既に存在しているため、代わりに変更する必要があります。
Junaid Qadir 2013年

4
「この制限は.NET Frameworkの機能であることを指摘することが重要だと思います」-むしろ、この種の機能は持たない方がいいです。
Herberth Amaral 2015

76

カスタムWebクライアントでこの問題に遭遇しました。これを行う方法が複数あるため、人々は混乱しているのではないかと思います。を使用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;を変更しました。to client.Headers.Add( "referer"、url); 物事はうまくいきます。ありがとう。
000

2
この回答には、デスクトップの.Netランタイムで作業していてhttpを要求しているという幸せな仮定が含まれていることに注意してください。WebRequest.Createは、使用するプロトコルプレフィックスに応じて、さまざまなオブジェクトを返すことができます。CustomProtocolHandlersに興味がある場合は、それに関連しています。そして、WP7またはSilverlightでは、リクエスト実装クラスも少し異なります。これには注意してください。
ケツァルコアトル2012

1
しかし、「Accept」ヘッダーを変更することはできません。これをどのように変更できますか?
ユーザー

最初の例でも同じエラーが発生します
mrid

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プロキシです。

プロパティを使用することが実際的または不可能であるシナリオは他にもたくさんあります。プロパティを使用してユーザーにヘッダーを設定することは、非常に柔軟性のない設計であるため、リフレクションが必要です。良い点は、リフレクションが抽象化されていること、それでも高速(テストでは0.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ため、ヘッダーを直接変更する必要はありません。プロパティを適切な値に設定するだけです。ContentLengthContentTypeUserAgent、など、すべての必要性は、このように設定します。

私見、これはMSの部分の欠点です...ヘッダーを設定するHeaders.Add()と、適切なプロパティがバックグラウンドで自動的に呼び出されます。


7

WebRequestは抽象的です(継承クラスはHeadersプロパティをオーバーライドする必要があるため)。具体的にどのWebRequestを使用していますか?言い換えれば、どのようにしてWebRequestオブジェクトを調整しますか?

ehr ..たくさんの答えは、あなたが得ていたエラーメッセージが実際にスポットされていることを私に認識させました:それはあなたが追加しようとしているヘッダーがすでに存在し、そして適切なプロパティ(例えばインデクサー、例えば)、もう一度追加するのではなく、それがおそらくあなたが探していたすべてです。

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

                        }
                    }

                }
            }
        } 

鮮やかさ!これにより、Webソケットの設定時に使用されるリクエストにこれらのヘッダーを設定して、この問題を回避することもできます。github.com
26627 –ØysteinKolsrud

それらはすべてヘッダーの操作にWebHeaderCollectionを使用するため、そうなるはずです。私はHttpWebRequestでのみテストしました。
スリーパー


0

以下に示すHttpWebRequestにWebRequestをキャストできます。

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

ヘッダーリストを操作する代わりに、リクエストプロパティrequest.Refererに直接適用します。

request.Referer = "yourReferer";

これらのプロパティは、リクエストオブジェクトで使用できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.