System.Net.WebRequestを使用している場合、一部のHTTPヘッダーを設定できません
-
04-07-2019 - |
質問
WebRequest
オブジェクトにHTTPヘッダーのキーと値のペアを追加しようとすると、次の例外が発生します:
このヘッダーは、適切なプロパティを使用して変更する必要があります
Add()メソッドを使用してHeaders
コレクションに新しい値を追加しようとしましたが、同じ例外が発生します。
webRequest.Headers.Add(HttpRequestHeader.Referer, "http://stackoverflow.com");
これを回避するには、WebRequestオブジェクトをHttpWebRequestにキャストし、httpWebReq.Referer ="http://stackoverflow.com"
などのプロパティを設定しますが、これはプロパティを介して公開される少数のヘッダーでのみ機能します。
リモートリソースのリクエストでヘッダーの変更をよりきめ細かく制御する方法があるかどうかを知りたい。
解決
短くて技術的な答えが必要な場合は、答えの最後のセクションに進んでください。
詳しく知りたい場合は、すべて読んでください。楽しんでいただければ幸いです...
今日もこの問題に対処しましたが、今日発見したのは次のとおりです:
-
上記の答えは次のとおりです:
1.1追加しようとしているヘッダーが既に存在することを示しているので、再度追加するのではなく、適切なプロパティ(インデクサーなど)を使用して値を変更する必要があります。
1.2
HttpWebRequest
のヘッダーを変更するときは常に、オブジェクト自体に適切なプロパティがあれば、それを使用する必要があります。
主要なガイドラインを作成してくれたFORとJvenemaに感謝します...
-
しかし、私が見つけたのは、それがパズルに欠けているピースでした:
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
したがって、次回この例外に直面し、これを解決する方法がわからない場合は、いくつかの制限されたヘッダーがあり、解決策はWebHeaderCollection.IsRestricted(key)
/ < =>クラス。
編集:(有用、コメントから、ユーザーによるコメント海道)
解決策は、addを呼び出す前に、ヘッダーがすでに存在するか、制限されているか(<=>)をチェックすることです
他のヒント
カスタム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();
これまでの回答はすべて、解決策を提供せずに問題を説明しています。文字列名を使用してヘッダーを設定できるようにすることで問題を解決する拡張メソッドを次に示します。
使用法
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>
を使用したいと考えました。
もう1つの例は、リクエストでヘッダーを取得し、受信者に転送する必要があるHTTPプロキシです。
プロパティを使用することが実用的ではない、または使用できないシナリオが他にもたくさんあります。プロパティを介してユーザーにヘッダーを設定することは非常に柔軟性に欠ける設計であるため、リフレクションが必要です。利点は、リフレクションが抽象化され、それでも高速(私のテストでは.001秒)であり、拡張メソッドが自然に感じられることです。
メモ
ヘッダー名では、RFCごとに大文字と小文字が区別されません。 http:/ /www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
HttpWebRequest
のヘッダーを変更する場合は常に、オブジェクト自体に適切なプロパティが存在する場合は、それを使用する必要があります。プレーンなWebRequest
がある場合は、最初にReferrer
にキャストしてください。この場合、((HttpWebRequest)request).Referrer
はContentLength
を介してアクセスできるため、ヘッダーを直接変更する必要はありません。プロパティを正しい値に設定するだけです。 ContentType
、UserAgent
、Headers.Add()
など、すべてこのように設定する必要があります。
IMHO、これはMSパーツの欠点です... <=>でヘッダーを設定すると、必要に応じて、舞台裏で適切なプロパティを自動的に呼び出す必要があります。
コードで<!> quot; Accept <!> quot;を設定しようとしたときに同じ例外が発生しました。このようなヘッダー値:
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";
WebRequest 抽象(および継承クラスはHeadersプロパティをオーバーライドする必要があるため)..どの具体的なWebRequestを使用していますか?言い換えれば、そのWebRequestオブジェクトをどのように使用するのですか?
ehr .. mnour答えは、あなたが得ていたエラーメッセージが実際にスポットであることを私に気づかせました:それはあなたが追加しようとしているヘッダーがすでに存在することを告げています、たとえば)、再度追加しようとする代わりに。おそらくあなたが探していたのはこれだけです。
WebRequestを継承する他のクラスには、特定のヘッダーをラップするより優れたプロパティがあります。 この投稿など。
上記の回答はすべて問題ありませんが、問題の本質は、一部のヘッダーが一方向に設定され、他のヘッダーが他の方法に設定されることです。 「制限付きヘッダー」リストについては、上記を参照してください。これらの場合、プロパティとして設定するだけです。その他の場合は、実際にヘッダーを追加します。こちらをご覧ください。
request.ContentType = "application/x-www-form-urlencoded";
request.Accept = "application/json";
request.Headers.Add(HttpRequestHeader.Authorization, "Basic " + info.clientId + ":" + info.clientSecret);
基本的に、いいえ。これはhttpヘッダーであるため、HttpWebRequest
にキャストして.Referer
を設定するのが合理的です(質問で示すとおり):
HttpWebRequest req = ...
req.Referer = "your url";
私はただ使用しています:
request.ContentType = "application/json; charset=utf-8"
WebRequestを以下に示すHttpWebRequestにキャストできます。
var request = (HttpWebRequest)WebRequest.Create(myUri);
そしてヘッダーリストを操作しようとする代わりに、リクエストプロパティrequest.Refererに直接適用します。
request.Referer = "yourReferer";
これらのプロパティはリクエストオブジェクトで利用可能です。