Impossible de définir certains en-têtes HTTP lors de l'utilisation de System.Net.WebRequest

StackOverflow https://stackoverflow.com/questions/239725

  •  04-07-2019
  •  | 
  •  

Question

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 Headers collection 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 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.

Était-ce utile?

La solution

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 mieux savoir, lisez le tout et j'espère que vous apprécierez ...

Je me suis aussi opposé à ce problème aujourd'hui, et ce que j'ai découvert aujourd'hui, c'est que:

  1. les réponses ci-dessus sont vraies, par exemple:

    1.1, il vous indique 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.

    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 grandes lignes directrices ...

  1. Mais, ce que j'ai découvert et c'est 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 saurez 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 WebHeaderCollection.IsRestricted(key) / <. => classe.

Modifier: (utile, à partir de commentaires, de commentaires de l'utilisateur Kaido )

  

La solution consiste à vérifier si l'en-tête existe déjà ou s'il est restreint (<=>) avant d'appeler add

.

Autres conseils

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 vers 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();

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’avantage, c’est que la réflexion est abstraite, elle est toujours rapide (0,001 seconde dans mes tests), et comme une méthode d’extension semble naturelle.

Notes

Les noms d'en-tête ne respectent pas la casse selon la 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 lui-même, si elles existent. Si vous avez un fichier WebRequest en clair, assurez-vous de le convertir en Referrer d’abord. Vous pouvez ensuite accéder à ((HttpWebRequest)request).Referrer dans votre cas via ContentLength, 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. ContentType, UserAgent, Headers.Add(), etc., doivent tous être définis de cette façon.

À mon humble avis, il s’agit là d’une lacune de la partie MS ... définir les en-têtes via <=> devrait automatiquement appeler la propriété appropriée dans les coulisses, si c’est ce qu’ils veulent faire.

J'ai eu la même exception lorsque mon code a essayé de définir le & "Accepter &"; valeur d'en-tête comme ceci:

WebRequest request = WebRequest.Create("http://someServer:6405/biprws/logon/long");
request.Headers.Add("Accept", "application/json");

La solution consistait à le changer en ceci:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://someServer:6405/biprws/logon/long");
request.Accept = "application/json";

WebRequest étant abstract (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 réponse m'a fait comprendre que le message d'erreur que vous obteniez est en fait sur place: il vous indique 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 cet article , par exemple.

Les réponses ci-dessus sont correctes, mais l’essentiel du problème est que certains en-têtes sont définis d’une manière, et d’autres 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. Voir 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. Il s’agit d’un en-tête http. Il est donc raisonnable de convertir le contenu en HttpWebRequest et de définir le .Referer (comme vous l’indiquez dans la question):

HttpWebRequest req = ...
req.Referer = "your url";

J'utilise seulement:

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

Vous pouvez simplement convertir WebRequest en une requête HttpWebRequest présentée ci-dessous:

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

et 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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top