Lorsque j'essaie d'ajouter une paire clé/valeur d'en-tête HTTP sur un objet WebRequest
, j'obtiens l'exception suivante:
Cet en-tête doit être modifié à l'aide de la propriété appropriée
J'ai essayé d'ajouter de nouvelles valeurs à la collection Headers
à l'aide de la méthode Add (), mais j'obtiens toujours la même exception.
webRequest.Headers.Add(HttpRequestHeader.Referer, "http://stackoverflow.com");
Je peux contourner ce problème en convertissant l'objet WebRequest en un HttpWebRequest et en définissant les propriétés telles que httpWebReq.Referer ="http://stackoverflow.com"
, mais cela ne fonctionne que pour une poignée d'en-têtes exposés via des propriétés.
J'aimerais savoir s'il existe un moyen d'obtenir un contrôle plus fin de la modification des en-têtes avec une demande de ressource distante.
Si vous avez besoin d'une réponse brève et technique, allez directement à la dernière section de la réponse.
Si vous voulez en savoir plus, lisez tout et j'espère que vous apprécierez ...
J'ai également contré ce problème aujourd'hui, et ce que j'ai découvert aujourd'hui, c'est que:
les réponses ci-dessus sont vraies, comme:
1.1, il vous dit que l'en-tête que vous essayez d'ajouter existe déjà et vous devriez alors modifier sa valeur en utilisant la propriété appropriée (l'indexeur, par exemple), au lieu d'essayer de l'ajouter à nouveau.
1.2 Chaque fois que vous modifiez les en-têtes d'un HttpWebRequest
, vous devez utiliser les propriétés appropriées sur l'objet lui-même, si elles existent.
Merci pour et Jvenema pour les directives de premier plan ...
Mais, ce que j’ai découvert et , c’était la pièce manquante du puzzle , c’est que:
2.1 La classe WebHeaderCollection
est généralement accessible via WebRequest
. En-têtes ou WebResponse
. En-têtes. Certains en-têtes courants sont considérés comme restreints et sont soit exposés directement par l'API (tels que Content-Type), soit protégés par le système et ne peuvent pas être modifiés.
Les en-têtes restreints sont:
Accept
Connection
Content-Length
Content-Type
Date
Expect
Host
If-Modified-Since
Range
Referer
Transfer-Encoding
User-Agent
Proxy-Connection
Ainsi, la prochaine fois que vous rencontrerez cette exception et que vous ne savez pas comment le résoudre, souvenez-vous qu'il existe des en-têtes restreints et que la solution consiste à modifier leurs valeurs à l'aide de la propriété appropriée de manière explicite à partir de WebRequest
/HttpWebRequest
classe.
Edit: (utile, à partir de commentaires, commentaire par utilisateur Kaido )
La solution consiste à vérifier si l'en-tête existe déjà ou s'il est restreint (
WebHeaderCollection.IsRestricted(key)
) avant d'appeler add
J'ai rencontré ce problème avec un client Web personnalisé. Je pense que les gens peuvent être déroutés à cause de multiples façons de le faire. Lorsque vous utilisez WebRequest.Create()
, vous pouvez transtyper en HttpWebRequest
et utiliser la propriété pour ajouter ou modifier un en-tête. Lorsque vous utilisez un WebHeaderCollection
, vous pouvez utiliser le .Add("referer","my_url")
.
Ex 1
WebClient client = new WebClient();
client.Headers.Add("referer", "http://stackoverflow.com");
client.Headers.Add("user-agent", "Mozilla/5.0");
Ex 2
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Referer = "http://stackoverflow.com";
request.UserAgent = "Mozilla/5.0";
response = (HttpWebResponse)request.GetResponse();
Toutes les réponses précédentes décrivent le problème sans fournir de solution. Voici une méthode d'extension qui résout le problème en vous permettant de définir n'importe quel en-tête via son nom de chaîne.
Utilisation
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.SetRawHeader("content-type", "application/json");
Classe d'extension
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;
}
}
}
Scénarios
J'ai écrit un wrapper pour HttpWebRequest
et je ne voulais pas exposer les 13 en-têtes restreints en tant que propriétés dans mon wrapper. Au lieu de cela, je voulais utiliser un simple Dictionary<string, string>
.
Un autre exemple est un proxy HTTP dans lequel vous devez prendre des en-têtes dans une demande et les transférer au destinataire.
Il y a beaucoup d'autres scénarios où il est tout simplement impossible ou possible d'utiliser des propriétés. Forcer l’utilisateur à définir l’en-tête via une propriété est une conception très rigide, c’est pourquoi une réflexion est nécessaire. L'aspect positif est que la réflexion est abstraite, qu'elle est toujours rapide (0,001 seconde dans mes tests) et qu'une méthode d'extension semble naturelle.
Notes
Les noms d'en-tête ne respectent pas la casse selon le RFC, http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
Chaque fois que vous modifiez les en-têtes d'un HttpWebRequest
, vous devez utiliser les propriétés appropriées sur l'objet même, si elles existent. Si vous avez un WebRequest
simple, assurez-vous de le convertir en HttpWebRequest
en premier. Ensuite, Referrer
dans votre cas peut être accédé via ((HttpWebRequest)request).Referrer
, Vous n'avez donc pas besoin de modifier l'en-tête directement, il vous suffit de définir la propriété sur la bonne valeur. ContentLength
, ContentType
, UserAgent
, etc., doivent tous être définis de cette façon.
IMHO, c'est une lacune sur la partie MS ... définir les en-têtes via Headers.Add()
devrait automatiquement appeler la propriété appropriée en coulisse, si c'est ce qu'ils veulent faire.
J'ai eu la même exception lorsque mon code a essayé de définir la valeur d'en-tête "Accept" comme ceci:
WebRequest request = WebRequest.Create("http://someServer:6405/biprws/logon/long");
request.Headers.Add("Accept", "application/json");
La solution était de changer cela en ceci:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://someServer:6405/biprws/logon/long");
request.Accept = "application/json";
WebRequest étant abstrait (et puisque toute classe héritante doit remplacer la propriété Headers) .. quelle WebRequest concrète utilisez-vous? En d'autres termes, comment obtenez-vous cet objet WebRequest?
ehr .. mnour answer m'a fait comprendre que le message d'erreur que vous obteniez est en fait sur place: il vous dit que l'en-tête que vous essayez d'ajouter existe déjà et que vous devez ensuite modifier sa valeur à l'aide de la propriété appropriée (l'indexeur, par exemple). ), au lieu d'essayer de l'ajouter à nouveau. C'est probablement tout ce que vous cherchiez.
D'autres classes héritant de WebRequest pourraient avoir des propriétés encore meilleures enveloppant certains en-têtes; Voir ce post par exemple.
Les réponses ci-dessus sont correctes, mais l'essentiel du problème réside dans le fait que certains en-têtes sont définis dans un sens et d'autres dans d'autres. Voir ci-dessus pour les listes 'en-tête restreint'. Pour ceux-ci, vous venez de les définir comme une propriété. Pour d'autres, vous ajoutez en fait l'en-tête. Vois ici.
request.ContentType = "application/x-www-form-urlencoded";
request.Accept = "application/json";
request.Headers.Add(HttpRequestHeader.Authorization, "Basic " + info.clientId + ":" + info.clientSecret);
En gros non. C’est un en-tête http, il est donc raisonnable de convertir en HttpWebRequest
et de définir le .Referer
_ (comme vous l'indiquez dans la question):
HttpWebRequest req = ...
req.Referer = "your url";
J'utilise juste:
request.ContentType = "application/json; charset=utf-8"
Vous pouvez simplement convertir WebRequest en un HttpWebRequest présenté ci-dessous:
var request = (HttpWebRequest)WebRequest.Create(myUri);
et ensuite, au lieu d'essayer de manipuler la liste d'en-têtes, appliquez-la directement dans la propriété de requête request.Referer:
request.Referer = "yourReferer";
Ces propriétés sont disponibles dans l'objet de requête.