web-dev-qa-db-fra.com

Problème d'encodage avec HttpWebResponse

Voici un extrait du code:

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();

Le problème est que si je teste avec: http://www.google.fr

Tous les "é" ne s'affichent pas bien. J'ai essayé de changer ASCII en UTF8 et l'affichage est toujours incorrect. J'ai testé le fichier html dans un navigateur et celui-ci affiche bien le texte html, alors je suis presque sûr que le problème provient de la méthode que j'utilise pour télécharger le fichier html.

Que devrais-je changer?

lien ImageShack mort supprimé

Mise à jour 1: Code et fichier de test modifiés

26
Patrick Desjardins

Premièrement, le moyen le plus simple d’écrire ce code est d’utiliser un StreamReader et un 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();
    }
}

Ensuite, il ne reste plus qu’à trouver le bon encodage. Comment avez-vous créé le fichier? Si c'est avec Notepad, vous voudrez probablement Encoding.Default - mais ce n'est évidemment pas portable, car c'est l'encodage par défaut pour votre PC.

Sur un serveur Web bien géré, la réponse indiquera le codage dans ses en-têtes. Cela dit, les en-têtes de réponse revendiquent parfois une chose et le code HTML en revendique une autre, dans certains cas.

25
Jon Skeet

CharacterSet est "ISO-8859-1" par défaut, s'il n'est pas spécifié dans l'en-tête de type de contenu du serveur (différent de la balise méta "charset" en HTML). Je compare HttpWebResponse.CharacterSet avec l'attribut charset de HTML. S'ils sont différents, j'utilise le jeu de caractères spécifié en HTML pour relire à nouveau la page, mais avec un codage correct cette fois-ci.

Voir le code: 

    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();
            }
        }
    }
29
Alex Dubinsky

Au cas où vous ne voudriez pas télécharger la page deux fois, j’ai légèrement modifié le code d’Alex à l’aide de Comment puis-je insérer WebResponse dans un flux de mémoire? . Voici le résultat

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

Il existe quelques bonnes solutions ici, mais elles semblent toutes essayer d’analyser le jeu de caractères dans la chaîne de type de contenu. Voici une solution utilisant System.Net.Mime.ContentType, qui devrait être plus fiable et plus courte.

 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);
3
stephenr85

C'est le code qui télécharge une fois.

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();
1
KinBread

J'ai étudié le même problème à l'aide de WireShark, un excellent analyseur de protocole. Je pense qu'il y a des problèmes de conception dans la classe httpWebResponse. En fait, l'entité de message entière a été téléchargée la première fois que vous avez appelé la méthode GetResponse () de la classe HttpWebRequest, mais le cadre n'a pas de place pour stocker les données dans la classe HttpWebResponse ou ailleurs, vous devez donc obtenir le flux de réponse. la deuxième fois.

0
Tony Zeng

Il existe encore quelques problèmes lors de la demande de la page Web "www.google.fr" à un WebRequest.

J'ai vérifié la demande brute et la réponse avec Fiddler. Le problème vient des serveurs de Google. Les en-têtes HTTP de réponse sont définis sur charset = ISO-8859-1, le texte lui-même est codé avec ISO-8859-1, tandis que le code HTML indique charset = UTF-8. Ceci est incohérent et conduit à des erreurs de codage.

Après de nombreux tests, j'ai réussi à trouver une solution de contournement. Il suffit d'ajouter :

myHttpWebRequest.UserAgent = "Mozilla/5.0";

à votre code, et Google Response deviendra comme par magie et entièrement UTF-8.

0
Etienne Coumont