Impossibile impostare alcune intestazioni HTTP quando si utilizza System.Net.WebRequest

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

  •  04-07-2019
  •  | 
  •  

Domanda

Quando provo ad aggiungere una coppia chiave / valore dell'intestazione HTTP su un oggetto WebRequest, ottengo la seguente eccezione:

  

Questa intestazione deve essere modificata utilizzando la proprietà appropriata

Ho provato ad aggiungere nuovi valori alla raccolta Headers usando il metodo Add () ma ho ancora la stessa eccezione.

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

Posso aggirare questo problema lanciando l'oggetto WebRequest su un HttpWebRequest e impostando le proprietà come httpWebReq.Referer ="http://stackoverflow.com", ma questo funziona solo per una manciata di intestazioni che sono esposte tramite le proprietà.

Mi piacerebbe sapere se esiste un modo per ottenere un controllo più preciso sulla modifica delle intestazioni con una richiesta per una risorsa remota.

È stato utile?

Soluzione

Se hai bisogno di una risposta breve e tecnica vai direttamente all'ultima sezione della risposta.

Se vuoi conoscere meglio, leggi tutto e spero che ti piacerà ...


Anche oggi ho contrastato questo problema, e quello che ho scoperto oggi è che:

  1. le risposte sopra riportate sono vere, come:

    1.1 ti sta dicendo che l'intestazione che stai tentando di aggiungere esiste già e dovresti quindi modificarne il valore usando la proprietà appropriata (l'indicizzatore, per esempio), invece di provare ad aggiungerla di nuovo.

    1.2 Ogni volta che si modificano le intestazioni di un HttpWebRequest, è necessario utilizzare le proprietà appropriate sull'oggetto stesso, se esistenti.

Grazie a FOR e Jvenema per le linee guida principali ...

  1. Ma quello che ho scoperto e quello era il pezzo mancante nel puzzle è che:

    2.1 Alla classe WebHeaderCollection si accede generalmente tramite WebRequest. Intestazioni o WebResponse. Intestazioni. Alcune intestazioni comuni sono considerate limitate e sono esposte direttamente dall'API (come Content-Type) o protette dal sistema e non possono essere modificate.

Le intestazioni limitate sono:

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

Quindi, la prossima volta che stai affrontando questa eccezione e non sai come risolverlo, ricorda che ci sono alcune intestazioni limitate e la soluzione è quella di modificare i loro valori usando esplicitamente la proprietà appropriata da WebHeaderCollection.IsRestricted(key) / < => classe.


Modifica: (utile, dai commenti, commento dell'utente Kaido )

  

La soluzione è verificare se l'intestazione esiste già o è limitata (<=>) prima di chiamare aggiungi

Altri suggerimenti

Ho riscontrato questo problema con un client Web personalizzato. Penso che le persone possano essere confuse a causa di molteplici modi per farlo. Quando si utilizza WebRequest.Create() è possibile eseguire il cast in un HttpWebRequest e utilizzare la proprietà per aggiungere o modificare un'intestazione. Quando si utilizza un WebHeaderCollection è possibile utilizzare .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();

Tutte le risposte precedenti descrivono il problema senza fornire una soluzione. Ecco un metodo di estensione che risolve il problema consentendo di impostare qualsiasi intestazione tramite il nome della stringa.

Utilizzo

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

Classe di estensione

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;
        }
    }
}

Scenari

Ho scritto un wrapper per HttpWebRequest e non volevo esporre tutte e 13 le intestazioni limitate come proprietà nel mio wrapper. Volevo invece usare un semplice Dictionary<string, string>.

Un altro esempio è un proxy HTTP in cui è necessario prendere le intestazioni in una richiesta e inoltrarle al destinatario.

Ci sono molti altri scenari in cui non è solo pratico o possibile usare le proprietà. Costringere l'utente a impostare l'intestazione tramite una proprietà è un progetto molto flessibile, motivo per cui è necessaria una riflessione. Il lato positivo è che il riflesso viene sottratto, è ancora veloce (0,001 secondi nei miei test) e come metodo di estensione sembra naturale.

Note

I nomi delle intestazioni non fanno distinzione tra maiuscole e minuscole per RFC, http: / /www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2

Ogni volta che si modificano le intestazioni di un HttpWebRequest, è necessario utilizzare le proprietà appropriate sull'oggetto stesso, se esistenti. Se hai un semplice WebRequest, assicurati di lanciarlo prima in Referrer. Quindi ((HttpWebRequest)request).Referrer nel tuo caso è possibile accedere tramite ContentLength, quindi non è necessario modificare direttamente l'intestazione: basta impostare la proprietà sul valore corretto. ContentType, UserAgent, Headers.Add(), ecc. devono essere impostati in questo modo.

IMHO, questo è un difetto nella parte MS ... l'impostazione delle intestazioni tramite <=> dovrebbe chiamare automaticamente la proprietà appropriata dietro le quinte, se è quello che vogliono fare.

Ho avuto la stessa eccezione quando il mio codice ha tentato di impostare il " Accetta " valore dell'intestazione come questo:

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

La soluzione è stata cambiarla in questo:

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

WebRequest essendo abstract (e poiché qualsiasi classe ereditaria deve sovrascrivere la proprietà Headers) .. quale richiesta Web concreta stai usando? In altre parole, come si ottiene quell'oggetto WebRequest con cui firmare?

ehr .. mnour answer mi ha fatto capire che il messaggio di errore che stavi ricevendo è effettivamente perfetto: ti sta dicendo che l'intestazione che stai cercando di aggiungere esiste già e dovresti quindi modificarne il valore usando la proprietà appropriata (l'indicizzatore , ad esempio), invece di provare ad aggiungerlo di nuovo. Questo è probabilmente tutto quello che stavi cercando.

Altre classi che ereditano da WebRequest potrebbero avere proprietà ancora migliori che racchiudono determinate intestazioni; Vedi questo post per esempio.

Le risposte di cui sopra vanno bene, ma l'essenza del problema è che alcune intestazioni sono impostate in un modo e altre in altri. Vedi sopra per gli elenchi di "intestazione riservata". Per questi, li hai appena impostati come proprietà. Per altri, in realtà aggiungi l'intestazione. Vedi qui.

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

    request.Accept = "application/json";

    request.Headers.Add(HttpRequestHeader.Authorization, "Basic " + info.clientId + ":" + info.clientSecret);

In sostanza, no. Questa è un'intestazione http, quindi è ragionevole eseguire il cast su HttpWebRequest e impostare .Referer (come indicato nella domanda):

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

Sto usando solo:

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

Puoi semplicemente trasmettere il WebRequest a un HttpWebRequest mostrato di seguito:

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

e quindi invece di provare a manipolare l'elenco di intestazioni, applicarlo direttamente nella richiesta di proprietà della richiesta. Referer:

request.Referer = "yourReferer";

Queste proprietà sono disponibili nell'oggetto richiesta.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top