No se pueden establecer algunas cabeceras HTTP cuando se utiliza System. Net. WebRequest


Cuando intento agregar un par clave/valor de encabezado HTTP en un objeto WebRequest, obtengo la siguiente excepción:

Este encabezado debe ser modificado usando la propiedad apropiada

He intentado agregar nuevos valores a la colección Headers usando el método Add (), pero todavía obtengo la misma excepción.

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

Puedo evitar esto lanzando el objeto WebRequest a un HttpWebRequest y estableciendo propiedades como httpWebReq.Referer ="http://stackoverflow.com", pero esto solo funciona para un puñado de encabezados que se exponen a través de propiedades.

Me gustaría saber si hay una manera de obtener un control más detallado sobre la modificación de encabezados con una solicitud de un recurso remoto.

Author: Vince Panuccio, 2008-10-27

10 answers

Si necesita la respuesta corta y técnica, vaya directamente a la última sección de la respuesta.

Si quieres saber mejor, léelo todo, y espero que lo disfrutes...


Yo también contrarresté este problema hoy, y lo que descubrí hoy es que:{[21]]}

  1. Las respuestas anteriores son verdaderas, como:

    1.1 le dice que el encabezado que está tratando de agregar ya existe y que debe modificar su valor utilizando la propiedad apropiada (el indexador, por ejemplo), en lugar de intentar añadirlo de nuevo.

    1.2 Cada vez que cambie los encabezados de un HttpWebRequest, debe usar las propiedades apropiadas en el objeto en sí, si existen.

Gracias y Jvenema por las directrices principales...

  1. Pero, lo que descubrí, y que era la pieza que faltaba en el rompecabezas es que:

    2.1 La clase WebHeaderCollection generalmente se accede a través de WebRequest.Cabeceras o WebResponse.Cabecera. Algunos los encabezados comunes se consideran restringidos y están expuestos directamente por la API (como Content-Type) o protegidos por el sistema y no se pueden cambiar.

Las cabeceras restringidas son:

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

So, la próxima vez que se enfrente a esta excepción y no sepa cómo resolver esto, recuerde que hay algunos encabezados restringidos, y la solución es modificar sus valores utilizando la propiedad apropiada explícitamente desde el WebRequest/HttpWebRequest clase.


Editar: (útil, de comentarios, comentario por usuario Kaido )

La solución es comprobar si el encabezado ya existe o está restringido (WebHeaderCollection.IsRestricted(key)) antes de llamar a add

 167
Author: dubi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 10:31:22

Me encontré con este problema con un cliente web personalizado. Creo que la gente puede estar confundiéndose debido a múltiples formas de hacer esto. Cuando se usa WebRequest.Create() se puede convertir a un HttpWebRequest y usar la propiedad para agregar o modificar un encabezado. Cuando se utiliza un WebHeaderCollection se puede utilizar el .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
Author: Chmod,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-16 19:52:27

Todas las respuestas anteriores describen el problema sin proporcionar una solución. Aquí hay un método de extensión que resuelve el problema al permitirle establecer cualquier encabezado a través de su nombre de cadena.

Uso

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

Clase de extensión

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

Escenarios

Escribí un wrapper para HttpWebRequest y no quería exponer las 13 cabeceras restringidas como propiedades en mi wrapper. En su lugar, quería usar un simple Dictionary<string, string>.

Otro ejemplo es un HTTP proxy donde necesita tomar encabezados en una solicitud y reenviarlos al destinatario.

Hay muchos otros escenarios donde simplemente no es práctico o posible usar propiedades. Forzar al usuario a establecer el encabezado a través de una propiedad es un diseño muy inflexible, por lo que se necesita reflexión. El lado positivo es que el reflejo se abstrae, sigue siendo rápido (.001 segundo en mis pruebas), y como un método de extensión se siente natural.

Notas

Nombres de encabezado son insensibles a mayúsculas y minúsculas por el RFC, http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2

 25
Author: Despertar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-25 08:19:37

Cada vez que cambie los encabezados de un HttpWebRequest, debe usar las propiedades apropiadas en el objeto en sí, si existen. Si tienes un WebRequest plano, asegúrate de lanzarlo a un HttpWebRequest primero. Entonces Referrer en su caso se puede acceder a través de ((HttpWebRequest)request).Referrer, por lo que no es necesario modificar el encabezado directamente - simplemente establecer la propiedad en el valor correcto. ContentLength, ContentType, UserAgent, etc, todo necesita ser establecido de esta manera.

En mi humilde opinión, esto es un defecto en la parte de MS...establecer los encabezados a través de Headers.Add() debería llame automáticamente a la propiedad apropiada detrás de escena, si eso es lo que quieren hacer.

 11
Author: jvenema,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-16 19:49:03

Tuve la misma excepción cuando mi código intentó establecer el valor de encabezado "Accept" de esta manera:

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

La solución fue cambiarlo a esto:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://someServer:6405/biprws/logon/long");
request.Accept = "application/json";
 8
Author: Mike Gledhill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-16 14:27:40

WebRequest siendo abstracta (y puesto que cualquier clase heredera debe sobreescribir la propiedad Headers).. ¿qué WebRequest concreto está utilizando ? En otras palabras, ¿cómo consigues que el objeto WebRequest se muestre?

Ehr.. mnour respuesta me hizo darme cuenta de que el mensaje de error que estaba recibiendo es en realidad el lugar: le está diciendo que el encabezado que está tratando de agregar ya existe y debe modificar su valor utilizando la propiedad apropiada (el indexador, por ejemplo), en lugar de intentar añadirlo de nuevo. Eso es probablemente todo lo que estabas buscando.

Otras clases heredadas de WebRequest podrían tener incluso mejores propiedades envolviendo ciertas cabeceras; Vea este post por ejemplo.

 7
Author: FOR,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-27 12:42:59

Básicamente, no. Eso es un encabezado http, por lo que es razonable convertir a HttpWebRequest y establecer el .Referer (como se indica en la pregunta):

HttpWebRequest req = ...
req.Referer = "your url";
 2
Author: Marc Gravell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-27 13:19:27

Todas las respuestas anteriores están bien, pero la esencia del problema es que algunos encabezados se establecen de una manera, y otros se establecen de otras maneras. Ver arriba para listas de 'encabezado restringido'. Para estos, solo los establece como una propiedad. Para otros, en realidad agrega el encabezado. Mira aquí.

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

    request.Accept = "application/json";

    request.Headers.Add(HttpRequestHeader.Authorization, "Basic " + info.clientId + ":" + info.clientSecret);
 2
Author: Rob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-30 17:35:03

Estoy usando solo:

request.ContentType = "application/json; charset=utf-8"
 0
Author: Stefan Michev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-11 17:16:47

Puede simplemente enviar la WebRequest a una HttpWebRequest que se muestra a continuación:

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

Y luego, en lugar de intentar manipular la lista de encabezados, aplíquela directamente en la propiedad request.Referer:

request.Referer = "yourReferer";

Estas propiedades están disponibles en el objeto request.

 0
Author: Bonomi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-24 14:48:42