Problemas de encoding con HttpWebResponse

Aquí hay un fragmento del código:

HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(request.RawUrl); WebRequest.DefaultWebProxy = null;//Ensure that we will not loop by going again in the proxy HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse(); string charSet = response.CharacterSet; Encoding encoding; if (String.IsNullOrEmpty(charSet)) encoding = Encoding.Default; else encoding = Encoding.GetEncoding(charSet); StreamReader resStream = new StreamReader(response.GetResponseStream(), encoding); return resStream.ReadToEnd(); 

El problema es si pruebo con: http://www.google.fr

Todos “é” no se muestran bien. Intenté cambiar ASCII por UTF8 y todavía muestra mal. He probado el archivo html en un navegador y el navegador muestra bien el texto html, así que estoy bastante seguro de que el problema está en el método que uso para descargar el archivo html.

¿Qué debería cambiar?

eliminado el enlace muerto de ImageShack

Actualización 1: cambio de código y archivo de prueba

En primer lugar, la forma más fácil de escribir ese código es usar un StreamReader y ReadToEnd:

 HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(myURL); using (HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse()) { using (Stream resStream = response.GetResponseStream()) { StreamReader reader = new StreamReader(resStream, Encoding.???); return reader.ReadToEnd(); } } 

Entonces es “solo” cuestión de encontrar la encoding correcta. ¿Cómo se creó el archivo? Si está en el Bloc de notas, probablemente quieras Encoding.Default , pero obviamente no es portátil, ya que es la encoding predeterminada para tu PC.

En un servidor web bien administrado, la respuesta indicará la encoding en sus encabezados. Una vez dicho esto, los encabezados de respuesta a veces reclaman una cosa y el HTML reclama otra, en algunos casos.

CharacterSet es “ISO-8859-1” por defecto, si no está especificado en el encabezado del tipo de contenido del servidor (diferente de la metaetiqueta “charset” en HTML). Comparo HttpWebResponse.CharacterSet con el atributo charset de HTML. Si son diferentes, utilizo el juego de caracteres como se especifica en HTML para volver a leer la página nuevamente, pero con la encoding correcta esta vez.

Ver el código:

  string strWebPage = ""; // create request System.Net.WebRequest objRequest = System.Net.HttpWebRequest.Create(sURL); // get response System.Net.HttpWebResponse objResponse; objResponse = (System.Net.HttpWebResponse)objRequest.GetResponse(); // get correct charset and encoding from the server's header string Charset = objResponse.CharacterSet; Encoding encoding = Encoding.GetEncoding(Charset); // read response using (StreamReader sr = new StreamReader(objResponse.GetResponseStream(), encoding)) { strWebPage = sr.ReadToEnd(); // Close and clean up the StreamReader sr.Close(); } // Check real charset meta-tag in HTML int CharsetStart = strWebPage.IndexOf("charset="); if (CharsetStart > 0) { CharsetStart += 8; int CharsetEnd = strWebPage.IndexOfAny(new[] { ' ', '\"', ';' }, CharsetStart); string RealCharset = strWebPage.Substring(CharsetStart, CharsetEnd - CharsetStart); // real charset meta-tag in HTML differs from supplied server header??? if(RealCharset!=Charset) { // get correct encoding Encoding CorrectEncoding = Encoding.GetEncoding(RealCharset); // read the web page again, but with correct encoding this time // create request System.Net.WebRequest objRequest2 = System.Net.HttpWebRequest.Create(sURL); // get response System.Net.HttpWebResponse objResponse2; objResponse2 = (System.Net.HttpWebResponse)objRequest2.GetResponse(); // read response using (StreamReader sr = new StreamReader(objResponse2.GetResponseStream(), CorrectEncoding)) { strWebPage = sr.ReadToEnd(); // Close and clean up the StreamReader sr.Close(); } } } 

En caso de que no desee descargar la página dos veces, modifiqué ligeramente el código de Alex usando ¿Cómo pongo una respuesta web en una secuencia de memoria? . Aquí está el resultado

 public static string DownloadString(string address) { string strWebPage = ""; // create request System.Net.WebRequest objRequest = System.Net.HttpWebRequest.Create(address); // get response System.Net.HttpWebResponse objResponse; objResponse = (System.Net.HttpWebResponse)objRequest.GetResponse(); // get correct charset and encoding from the server's header string Charset = objResponse.CharacterSet; Encoding encoding = Encoding.GetEncoding(Charset); // read response into memory stream MemoryStream memoryStream; using (Stream responseStream = objResponse.GetResponseStream()) { memoryStream = new MemoryStream(); byte[] buffer = new byte[1024]; int byteCount; do { byteCount = responseStream.Read(buffer, 0, buffer.Length); memoryStream.Write(buffer, 0, byteCount); } while (byteCount > 0); } // set stream position to beginning memoryStream.Seek(0, SeekOrigin.Begin); StreamReader sr = new StreamReader(memoryStream, encoding); strWebPage = sr.ReadToEnd(); // Check real charset meta-tag in HTML int CharsetStart = strWebPage.IndexOf("charset="); if (CharsetStart > 0) { CharsetStart += 8; int CharsetEnd = strWebPage.IndexOfAny(new[] { ' ', '\"', ';' }, CharsetStart); string RealCharset = strWebPage.Substring(CharsetStart, CharsetEnd - CharsetStart); // real charset meta-tag in HTML differs from supplied server header??? if (RealCharset != Charset) { // get correct encoding Encoding CorrectEncoding = Encoding.GetEncoding(RealCharset); // reset stream position to beginning memoryStream.Seek(0, SeekOrigin.Begin); // reread response stream with the correct encoding StreamReader sr2 = new StreamReader(memoryStream, CorrectEncoding); strWebPage = sr2.ReadToEnd(); // Close and clean up the StreamReader sr2.Close(); } } // dispose the first stream reader object sr.Close(); return strWebPage; } 

Aquí hay algunas buenas soluciones, pero todas parecen estar tratando de analizar el conjunto de caracteres de la cadena de tipo de contenido. Aquí hay una solución que usa System.Net.Mime.ContentType, que debería ser más confiable y más corta.

  var client = new System.Net.WebClient(); var data = client.DownloadData(url); var encoding = System.Text.Encoding.Default; var contentType = new System.Net.Mime.ContentType(client.ResponseHeaders[HttpResponseHeader.ContentType]); if (!String.IsNullOrEmpty(contentType.CharSet)) { encoding = System.Text.Encoding.GetEncoding(contentType.CharSet); } string result = encoding.GetString(data); 

Este es un código que se descarga una vez.

 String FinalResult = ""; HttpWebRequest Request = (HttpWebRequest)System.Net.WebRequest.Create( URL ); HttpWebResponse Response = (HttpWebResponse)Request.GetResponse(); Stream ResponseStream = Response.GetResponseStream(); StreamReader Reader = new StreamReader( ResponseStream ); bool NeedEncodingCheck = true; while( true ) { string NewLine = Reader.ReadLine(); // it may not working for zipped HTML. if( NewLine == null ) { break; } FinalResult += NewLine; FinalResult += Environment.NewLine; if( NeedEncodingCheck ) { int Start = NewLine.IndexOf( "charset=" ); if( Start > 0 ) { Start += "charset=\"".Length; int End = NewLine.IndexOfAny( new[] { ' ', '\"', ';' }, Start ); Reader = new StreamReader( ResponseStream, Encoding.GetEncoding( NewLine.Substring( Start, End - Start ) ) ); // Replace Reader with new encoding. NeedEncodingCheck = false; } } } Reader.Close(); Response.Close(); 

Estudié el mismo problema con la ayuda de WireShark, un excelente analizador de protocolos. Creo que hay algún diseño corto llegando a la clase httpWebResponse. De hecho, toda la entidad de mensaje se descargó la primera vez que invocó el método GetResponse () de la clase HttpWebRequest, pero el marco no tiene lugar para almacenar los datos en la clase HttpWebResponse o en otro lugar, lo que significa que debe obtener la secuencia de respuesta la segunda vez.

Todavía hay algunos problemas al solicitar la página web “www.google.fr” desde una WebRequest.

Comprobé la solicitud y respuesta sin procesar con Fiddler. El problema proviene de los servidores de Google. Los encabezados HTTP de respuesta se establecen en charset = ISO-8859-1, el texto en sí está codificado con ISO-8859-1, mientras que el HTML dice charset = UTF-8. Esto es incoherente y conduce a errores de encoding.

Después de muchas pruebas, logré encontrar una solución alternativa. Solo agrega :

 myHttpWebRequest.UserAgent = "Mozilla/5.0"; 

a su código, y Google Response se convertirá mágicamente y por completo en UTF-8.