2009-12-11 18 views
8

Tengo el siguiente problema. Me pongo en contacto con una dirección que sé que emplea un redireccionamiento 301.C# HttpWebResponse Codificación del encabezado

usando HttpWebRequest loHttp = (HttpWebRequest)WebRequest.Create(lcUrl); y loHttp.AllowAutoRedirect = false; para que no se me redirija.

Ahora obtengo el encabezado de la respuesta para identificar la nueva url.

usando loWebResponse.GetResponseHeader("Location");

El problema es que desde esta URL contiene caracteres griegos la cadena devuelta es todo revuelto (debido a la codificación).

El codewise imagen completa:

HttpWebRequest loHttp = (HttpWebRequest)WebRequest.Create(lcUrl); 
loHttp.ContentType = "application/x-www-form-urlencoded"; 
loHttp.Method = "GET"; 

Timeout = 10000; 

loHttp.AllowAutoRedirect = false; 
HttpWebResponse loWebResponse = (HttpWebResponse)loHttp.GetResponse(); 

string url= loWebResponse.Headers["Location"]; 
+1

De manera predeterminada, 'HttpWebRequest' seguirá los redireccionamientos, por lo que si un servidor envía el código de estado' 301/302' se emitirá una nueva solicitud para recuperar el recurso usando el encabezado 'Location'. Así que una vez que este recurso final sea recuperado, ya no habrá un encabezado 'Location' en la respuesta, entonces me pregunto cómo es que' loWebResponse.GetResponseHeader ("Location") 'devuelve algo que no sea una cadena vacía. Dejando esto a un lado, ¿has verificado con 'FireBug' que el sitio realiza una codificación correcta en el encabezado' Location'? –

+1

No dejé en claro que 'loHttp.AllowAutoRedirect = false;' está configurado para que pueda inspeccionar el URL de redirección –

Respuesta

6

Si deja que el comportamiento predeterminado (loHttp.AllowAutoRedirect = true) y su código no funcione (no se le redirige al nuevo recurso) significa que el servidor no está codificando correctamente el encabezado Location. ¿La redirección funciona en el navegador?

Por ejemplo, si la URL de redirección es http://site/Μία_Σελίδα, el encabezado de la ubicación debe ser http://site/%CE%95%CE%BD%CE%B9%CE%B1%CE%AF%CE%BF_%CE%94%CE%B5%CE%.


ACTUALIZACIÓN:

Después de investigar más el asunto empiezo a sospechar que hay algo extraño con HttpWebRequest. Cuando la solicitud se envía al servidor envía la siguiente respuesta:

HTTP/1.1 301 Moved Permanently 
Date: Fri, 11 Dec 2009 17:01:04 GMT 
Server: Microsoft-IIS/6.0 
X-Powered-By: ASP.NET 
Location: http://www.site.com/buy/κινητή-σταθερή-τηλεφωνία/c/cn69569/ 
Content-Length: 112 
Content-Type: text/html; Charset=UTF-8 
Cache-control: private 
Connection: close 
Set-Cookie: BIGipServerpool_webserver_gr=1007732746.36895.0000; path=/ 


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 

Como podemos ver en la cabecera Location contiene caracteres griegos que no están codificados URL. No estoy seguro si esto es válido de acuerdo con HTTP specification. Lo que sí podemos decir con certeza es que un navegador web lo interpreta correctamente.

Aquí viene la parte interesante. Parece que HttpWebRequest no utiliza la codificación UTF-8 para analizar los encabezados de respuesta porque al analizar el encabezado Location se obtiene: http://www.site.com/buy/κινηÏή-ÏÏαθεÏή-ÏηλεÏÏνία/c/cn69569/, lo que por supuesto es incorrecto y cuando intenta redireccionar a esta ubicación el servidor responde con un nuevo redireccionamiento y etc. hasta que se alcanza el número máximo de redireccionamientos y se lanza una excepción.

No pude encontrar ninguna forma de especificar la codificación utilizada por HttpWebRequest al analizar los encabezados de respuesta. Si utilizamos TcpCLient manualmente funciona perfectamente bien:

using (var client = new TcpClient()) 
{ 
    client.Connect("www.site.com", 80); 

    using (var stream = client.GetStream()) 
    { 
     var writer = new StreamWriter(stream); 
     writer.WriteLine("GET /default/defaultcatg.asp?catg=69569 HTTP/1.1"); 
     writer.WriteLine("Host: www.site.com"); 
     writer.WriteLine("User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.2) Gecko/20090805 Shiretoko/3.5.2"); 
     writer.WriteLine("Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); 
     writer.WriteLine("Accept-Language: en-us,en;q=0.5"); 
     writer.WriteLine("Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7"); 
     writer.WriteLine("Connection: close"); 
     writer.WriteLine(string.Empty); 
     writer.WriteLine(string.Empty); 
     writer.WriteLine(string.Empty); 
     writer.Flush(); 

     var reader = new StreamReader(stream); 
     var response = reader.ReadToEnd(); 
     // When looking at the response it correctly reads 
     // Location: http://www.site.com/buy/κινητή-σταθερή-τηλεφωνία/c/cn69569/ 
    } 
} 

así que estoy muy intrigado por este comportamiento. ¿Hay alguna forma de especificar la codificación correcta utilizada por HttpWebRequest? Tal vez algún encabezado de solicitud debe establecerse?

Como solución alternativa puede intentar modificar la página asp que realiza el redireccionamiento y urlencode el encabezado Location. Por ejemplo, cuando en una aplicación ASP.NET realiza un Response.Redirect(location), la ubicación se codificará html automáticamente y los caracteres no estándar se convertirán a sus entidades correspondientes.

Por ejemplo si lo hace: Response.Redirect("http://www.site.com/buy/κινητή-σταθερή-τηλεφωνία/c/cn69569/"); en una aplicación ASP.NET la cabecera Location se establecerá en:

http://www.site.com/buy/%ce%ba%ce%b9%ce%bd%ce%b7%cf%84%ce%ae-%cf%83%cf%84%ce%b1%ce%b8%ce%b5%cf%81%ce%ae-%cf%84%ce%b7%ce%bb%ce%b5%cf%86%cf%89%ce%bd%ce%af%ce%b1/c/cn69569 

Parece que este no es el caso con ASP clásico.

+0

si la dejo como verdadera, entonces recibo una excepción (ya sea un tiempo de espera o una excepción de redirecciones máximas). En el navegador funciona bien en términos de llegar a la página correcta. Así que supongo que estoy haciendo algo mal al leer los encabezados de ubicación. –

+0

¿Hay alguna posibilidad de que puedas publicar la URL real para que pueda echarle un vistazo? ¿O tal vez no es públicamente accesible? –

+2

En .Net, el análisis sintáctico de los encabezados se maneja en una codificación "pura ASCII" que se encapsula dentro de la clase WebHeaderCollection. Esto está de acuerdo con RFC 2616. Quienquiera que distribuya ese encabezado de ubicación lo está haciendo mal, pero la mayoría de los navegadores "simplemente lo manejan", suponiendo que el juego de caracteres es UTF-8 (lo que hay en la corriente de octeto real). – IDisposable

1

yo no esperaría que la cadena devuelta a ser malformado ... ¿cómo te determinar que es mal formado? La cadena debe estar en formato unicode como utf-8 que pueda representar fácilmente la cadena griega.

¿Podría ser que simplemente no tiene las fuentes griegas para representar la cadena?

+0

por malformado, quiero decir, no en una codificación legible. esto es lo que la vuelve getResponseHeader "http://www.site.com/buy/κινηÏή-ÏÏαθÎμÏή-ÏηλÎμÏÏνία/c/cn69569/" –

+0

hmmm en Visual Studio parece un poco diferente: S pero igual como ves, la parte media se arruinó –

1

Como explica Darin Dimitrov, creo que la codificación del encabezado es causada por un error en la clase HttpWebResponse. Hemos tenido el mismo problema en el que queríamos agregar una cookie al encabezado (Set-Cookie) y esta cookie contendría caracteres no Ascii. En nuestro caso específico, esta sería la letra noruega 'Æ', 'Ø' y 'Å' (en mayúscula y minúscula). No pudimos encontrar la forma de hacer que funcione el HeaderEncoding, pero encontramos una solución temporal que usa Base64-codificación de la cookie. Tenga en cuenta que esto solo funcionará si tiene el control del lado del cliente y del servidor (o puede convencer a las personas a cargo del código del servidor para agregar la codificación Base64 ...)

en el lado del servidor:

var cookieData = "This text contains Norwegian letters; ÆØÅæøå"; 
var cookieDataAsUtf8Bytes = System.Text.Encoding.UTF8.GetBytes(cookieData); 
var cookieDataAsUtf8Base64Encoded = Convert.ToBase64String(cookieDataAsUtf8Bytes); 
var cookie = new HttpCookie("MyCookie", cookieDataAsUtf8Base64Encoded); 
response.Cookies.Add(cookie); 

en el lado del cliente:

var cookieDataAsUtf8Bytes = Convert.FromBase64String(cookieDataAsUtf8Base64Encoded); 
var cookieData = System.Text.Encoding.UTF8.GetString(cookieDataAsUtf8Bytes); 

Tenga en cuenta que cookieDataAsUtf8Base64Encoded en el lado del cliente es la parte de datos de la cookie (es decir 'MyCookie = [datos]', donde 'MyCookie =' es eliminado).

Cuestiones relacionadas