c# - unidades - Problemas de codificación con HttpWebResponse
encoding:: utf8 (7)
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
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 codificación.
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.
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 codificación 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 codificación predeterminada para tu PC.
En un servidor web bien administrado, la respuesta indicará la codificación 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 codificación 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();
}
}
}
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, la entidad de mensaje completa 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.
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();
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);
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;
}