Si vous avez besoin d'une réponse courte et technique, passez directement à la dernière section de la réponse.
Si vous voulez en savoir plus, lisez tout cela et j'espère que vous apprécierez ...
J'ai également combattu 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 cela vous indique que l'en-tête que vous essayez d'ajouter existe déjà et que vous devez 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 principales directives ...
Mais, ce que j'ai découvert, et c'était la pièce manquante dans le puzzle, c'est que:
2.1 La WebHeaderCollection
classe est généralement accessible via WebRequest
.Headers ou WebResponse
.Headers. Certains en-têtes courants sont considérés comme restreints et sont soit exposés directement par l'API (comme 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 rencontrez cette exception et que vous ne savez pas comment résoudre cela, rappelez-vous qu'il existe des en-têtes restreints et que la solution est de modifier leurs valeurs en utilisant la propriété appropriée explicitement de la classe WebRequest
/ HttpWebRequest
.
Edit: (utile, à partir des commentaires, commentaire de l'utilisateur Kaido )
La solution consiste à vérifier si l'en-tête existe déjà ou est restreint ( WebHeaderCollection.IsRestricted(key)
) avant d'appeler add
Headers.Add()
existe déjà, nous devrions donc la modifier à la place.J'ai rencontré ce problème avec un client Web personnalisé. Je pense que les gens peuvent être confus à cause de plusieurs façons de le faire. Lors de l'utilisation,
WebRequest.Create()
vous pouvez effectuer un cast enHttpWebRequest
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
Ex 2
la source
Toutes les réponses précédentes décrivent le problème sans apporter 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.
Usage
Classe d'extension
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 simpleDictionary<string, string>
.Un autre exemple est un proxy HTTP dans lequel vous devez prendre des en-têtes dans une requête et les transmettre au destinataire.
Il existe de nombreux autres scénarios où il n'est tout simplement pas pratique 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'avantage est que la réflexion est abstraite, elle est toujours rapide (0,001 seconde dans mes tests) et, en tant que méthode d'extension, elle semble naturelle.
Remarques
Les noms d'en-tête sont insensibles à la casse selon la RFC, http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
la source
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); } } }
J'ai eu la même exception lorsque mon code a essayé de définir la valeur d'en-tête "Accepter" comme ceci:
La solution était de le changer en ceci:
la source
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. Si vous avez une plaineWebRequest
, assurez-vous de la lancer enHttpWebRequest
premier. Ensuite,Referrer
dans votre cas, vous pouvez accéder via((HttpWebRequest)request).Referrer
, vous n'avez donc pas besoin de modifier l'en-tête directement - définissez simplement la propriété sur la bonne valeur.ContentLength
,ContentType
,UserAgent
, Etc, doivent tous être mis de cette façon.À mon humble avis, c'est une lacune de la part de MS ... la définition des en-têtes via
Headers.Add()
devrait automatiquement appeler la propriété appropriée dans les coulisses, si c'est ce qu'ils veulent faire.la source
WebRequest étant abstrait (et puisque toute classe héritière doit remplacer la propriété Headers) .. quelle WebRequest concrète utilisez-vous? En d'autres termes, comment obtenir cet objet WebRequest avec lequel s'aligner?
ehr .. ma réponse m'a fait réaliser que le message d'erreur que vous obteniez est en fait parfait: il vous dit que l'en-tête que vous essayez d'ajouter existe déjà et que vous devez ensuite modifier sa valeur en utilisant la propriété appropriée (l'indexeur, par exemple ), au lieu d'essayer de l'ajouter à nouveau. C'est probablement tout ce que vous recherchiez.
D'autres classes héritant de WebRequest peuvent avoir des propriétés encore meilleures encapsulant certains en-têtes; Voir cet article par exemple.
la source
Les réponses ci-dessus sont toutes correctes, mais l'essence du problème est que certains en-têtes sont définis dans un sens et d'autres dans d'autres. Voir ci-dessus pour les listes «d'en-têtes restreints». Pour ceux-ci, vous les définissez simplement comme une propriété. Pour les autres, vous ajoutez en fait l'en-tête. Vois ici.
la source
En gros, non. Il s'agit d'un en-tête http, il est donc raisonnable de convertir
HttpWebRequest
et de définir le.Referer
(comme vous l'indiquez dans la question):la source
Remarque: cette solution fonctionnera avec WebClientSocket ainsi qu'avec HttpWebRequest ou toute autre classe qui utilise WebHeaderCollection pour travailler avec les en-têtes.
Si vous regardez le code source de WebHeaderCollection.cs, vous verrez que Hinfo est utilisé pour conserver les informations de tous les en-têtes connus:
En regardant la classe HeaderInfoTable, vous pouvez remarquer que toutes les données sont stockées dans une table de hachage
En outre, dans le constructeur statique de HeaderInfoTable, vous pouvez voir que tous les en-têtes connus sont ajoutés dans le tableau HeaderInfo, puis copiés dans la table de hachage.
Un dernier regard sur la classe HeaderInfo montre les noms des champs.
Donc, avec tout ce qui précède, voici un code qui utilise la réflexion pour trouver Hashtable statique dans la classe HeaderInfoTable, puis modifie chaque HeaderInfo restreint à la demande dans la table de hachage pour ne pas être restreint
la source
J'utilise juste:
la source
Vous pouvez simplement convertir la WebRequest en une HttpWebRequest présentée ci-dessous:
puis au lieu d'essayer de manipuler la liste des en-têtes, appliquez-la directement dans la demande de propriété de la requête.
Ces propriétés sont disponibles dans l'objet de requête.
la source