web-dev-qa-db-ja.com

System.Net.WebRequestを使用している場合、一部のHTTPヘッダーを設定できません

WebRequestオブジェクトにHTTPヘッダーのキーと値のペアを追加しようとすると、次の例外が発生します。

このヘッダーは、適切なプロパティを使用して変更する必要があります

Add()メソッドを使用してHeadersコレクションに新しい値を追加しようとしましたが、同じ例外が発生します。

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

これを回避するには、WebRequestオブジェクトをHttpWebRequestにキャストし、httpWebReq.Referer ="http://stackoverflow.com"などのプロパティを設定しますが、これはプロパティを介して公開される少数のヘッダーに対してのみ機能します。

リモートリソースのリクエストでヘッダーを変更する際に、よりきめ細かな制御を行う方法があるかどうかを知りたいです。

124
Vince Panuccio

短くて技術的な答えが必要な場合は、答えの最後のセクションに進んでください。

もっとよく知りたい場合は、すべてを読んで、楽しんでください...


今日もこの問題に対処しましたが、今日私が発見したのはそれです:

  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クラスから適切なプロパティを明示的に使用して値を変更することです。


編集:(有用、コメントから、ユーザーによるコメント 海道

解決策は、addを呼び出す前に、ヘッダーが既に存在するか、制限されているか(WebHeaderCollection.IsRestricted(key))確認することです。

177
dubi

カスタム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();
71
Chmod

上記の回答はすべて、解決策を提供せずに問題を説明しています。文字列名を使用してヘッダーを設定できるようにすることで問題を解決する拡張メソッドを次に示します。

使用法

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

28
Despertar

HttpWebRequestのヘッダーを変更するときは常に、オブジェクト自体に適切なプロパティがあれば、それを使用する必要があります。プレーンWebRequestがある場合は、必ず最初にHttpWebRequestにキャストしてください。その後、Referrer((HttpWebRequest)request).Referrer経由でアクセスできるため、ヘッダーを直接変更する必要はありません-プロパティを適切な値に設定するだけです。 ContentLengthContentTypeUserAgentなど、すべてこの方法で設定する必要があります。

私見、これはMS部分の欠点です... Headers.Add()を介してヘッダーを設定すると、必要に応じて、舞台裏で適切なプロパティを自動的に呼び出す必要があります。

12
jvenema

私のコードが次のように「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
Mike Gledhill

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

ehr .. mnour answerは、あなたが得ていたエラーメッセージが実際にスポットであることを私に気づかせました:それはあなたが追加しようとしているヘッダーがすでに存在し、適切なプロパティ(たとえばインデクサー、 )、再度追加しようとする代わりに。おそらくあなたが探していたのはこれだけです。

WebRequestから継承する他のクラスには、特定のヘッダーをラップするより優れたプロパティがあります。 this post を参照してください。

7
FOR

上記の答えはすべて問題ありませんが、問題の本質は、一部のヘッダーが一方向に設定され、他のヘッダーが他の方法に設定されることです。 「制限付きヘッダー」リストについては上記を参照してください。これらの場合、プロパティとして設定するだけです。その他の場合は、実際にヘッダーを追加します。こちらをご覧ください。

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

    request.Accept = "application/json";

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

基本的にはありません。これはhttpヘッダーなので、HttpWebRequestにキャストして.Refererを設定するのが妥当です(質問で示したとおり)。

HttpWebRequest req = ...
req.Referer = "your url";
1
Marc Gravell

私はちょうど使用しています:

request.ContentType = "application/json; charset=utf-8"
0
Stefan Michev

以下に示すHttpWebRequestにWebRequestをキャストするだけです。

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

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

request.Referer = "yourReferer";

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

0
Bonomi