Impossible de définir certains en-têtes HTTP lors de L'utilisation du système.Net.WebRequest

quand 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é en utilisant la propriété appropriée

j'ai essayé d'ajouter de nouvelles valeurs à la collection Headers en utilisant la méthode Add() mais j'obtiens toujours la même exception.

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

je peux contourner cela en jetant L'objet WebRequest à un HttpWebRequest et le réglage des propriétés telles que httpWebReq.Referer ="http://stackoverflow.com" , mais cela ne fonctionne que pour une poignée de en-têtes qui sont exposés via des propriétés.

j'aimerais savoir s'il y a un moyen d'obtenir un contrôle plus fin sur la modification des en-têtes avec une demande pour une ressource à distance.

116
demandé sur Vince Panuccio 2008-10-27 15:32:02

10 réponses

si vous avez besoin de la réponse courte et technique, allez directement à la dernière section de la réponse.

Si vous voulez connaître mieux, tout lu, et j'espère que vous apprécierez...


j'ai répliqué ce problème aussi, aujourd'hui, et ce que j'ai découvert aujourd'hui que:

  1. les réponses ci-dessus sont remplies, comme:

    1.1 il vous dit que l'en-tête que vous essayez pour ajouter existent 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 changez 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.

Grâce et Jvenema pour les principales lignes directrices...

  1. Mais, Ce que j'ai découvert, et qui était la pièce manquante dans le puzzle est que:

    2.1 La classe WebHeaderCollection est généralement accessible par WebRequest .En-têtes ou WebResponse .Tête. certains en-têtes courants sont considérés comme restreints et sont exposés directement par L'API (comme le type de contenu) ou protégés par le système et ne peuvent pas être changés.

restreint les en-têtes sont:

  • Accept
  • Connection
  • Content-Length
  • Content-Type
  • Date
  • Expect
  • Host
  • If-Modified-Since
  • Range
  • Referer
  • Transfer-Encoding
  • User-Agent
  • Proxy-Connection

donc, la prochaine fois que vous faites face à cette exception et que vous ne savez pas comment résoudre cela, rappelez-vous qu'il y a des en-têtes restreints, et la solution est de modifier leurs valeurs en utilisant la propriété appropriée explicitement de la classe WebRequest / HttpWebRequest .


Edit: (utile, d'après les commentaires, commentaire de l'utilisateur Kaido )

Solution est de vérifier si l'en-tête existe déjà ou est restreint ( WebHeaderCollection.IsRestricted(key) ) avant d'appeler ajouter

167
répondu dubi 2017-05-23 10:31:22

j'ai rencontré ce problème avec un client web. Je pense que les gens peuvent être confus à cause de plusieurs façons de faire cela. En utilisant WebRequest.Create() vous pouvez lancer à un 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();
67
répondu Chmod 2012-05-16 19:52:27

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.

Utilisation

HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.SetRawHeader("content-type", "application/json");

Extension De La Classe

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 emballage pour HttpWebRequest et je ne voulais pas exposer les 13 en-têtes restreints comme propriétés dans mon emballage. Au lieu de cela, je voulais utiliser un simple Dictionary<string, string> .

un autre exemple est un mandataire HTTP où vous devez prendre des en-têtes dans une requête et les transmettre au destinataire.

Il ya beaucoup d'autres scénarios où il est tout simplement pas pratique ou possible d'utiliser des propriétés. Forcer l'utilisateur de définir l'en-tête via une propriété est une très rigides conception qui est pourquoi une réflexion est nécessaire. Le le côté positif est que le reflet est abstrait loin, il est encore rapide (.001 seconde dans mes tests), et comme une méthode d'extension se sent naturel.

Notes

les noms D'en-tête sont insensibles à la casse selon la RFC, http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2

25
répondu Despertar 2015-11-25 08:19:37

chaque fois que vous changez 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 un WebRequest Uni , assurez-vous de le mouler à un HttpWebRequest d'abord. Puis Referrer dans votre cas peut être accédé via ((HttpWebRequest)request).Referrer , de sorte que vous n'avez pas besoin de modifier l'en - tête directement-il suffit de définir la propriété à la bonne valeur. ContentLength , ContentType , UserAgent , etc, tout doit être réglé de cette façon.

IMHO, c'est une lacune de la part de MS...le réglage 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.

11
répondu jvenema 2012-05-16 19:49:03

j'ai eu la même exception lorsque mon code a essayé de définir la valeur de l'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 le changer en ceci:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://someServer:6405/biprws/logon/long");
request.Accept = "application/json";
8
répondu Mike Gledhill 2016-03-16 14:27:40

WebRequest étant abstrait (et puisque toute classe héritant doit primer la propriété Headers).. quelle WebRequest concrète utilisez-vous ? En d'autres termes, comment faire pour que L'objet WebRequest baigne ?

ehr.. mnour answer m'a fait réaliser que le message d'erreur que vous obteniez est en fait spot sur: il vous dit que l'en-tête que vous essayez d'ajouter existent déjà et vous devriez alors modifier sa valeur en utilisant le approprié de la propriété (l'indexeur, par exemple), au lieu d'essayer de l'ajouter à nouveau. C'est probablement tout que vous recherchez.

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.

7
répondu FOR 2008-10-27 12:42:59

en gros, non. C'est un en-tête http, il est donc raisonnable de cast de HttpWebRequest et .Referer (comme vous l'indiquez dans la question):

HttpWebRequest req = ...
req.Referer = "your url";
2
répondu Marc Gravell 2008-10-27 13:19:27

Les réponses ci-dessus sont tous très bien, mais le fond du problème, c'est que certains en-têtes sont définies d'une façon et d'autres sont d'autres façons. Voir ci-dessus pour les listes' en-tête restreint'. Pour celles-ci, vous les mettez en propriété. Pour les autres, vous avez réellement ajouter l'en-tête. Voir ici.

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

    request.Accept = "application/json";

    request.Headers.Add(HttpRequestHeader.Authorization, "Basic " + info.clientId + ":" + info.clientSecret);
2
répondu Rob 2014-12-30 17:35:03

j'utilise juste:

request.ContentType = "application/json; charset=utf-8"
0
répondu Stefan Michev 2015-03-11 17:16:47

vous pouvez simplement lancer le WebRequest à un HttpWebRequest montré ci-dessous:

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

et ensuite au lieu d'essayer de manipuler la liste d'en-tête, appliquez-la directement dans la requête de propriété request.Referer:

request.Referer = "yourReferer";

ces propriétés sont disponibles dans l'objet request.

0
répondu Bonomi 2015-04-24 14:48:42