Проблема с кодировкой HttpWebResponse - PullRequest
26 голосов
/ 23 октября 2008

Вот фрагмент кода:

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

Проблема в том, что если я тестирую с: http://www.google.fr

Все "é" отображаются плохо. Я пытался изменить ASCII на UTF8, и он по-прежнему отображается неправильно. Я протестировал html-файл в браузере, и браузер хорошо отображает html-текст, поэтому я почти уверен, что проблема в том, какой метод я использую для загрузки html-файла.

Что я должен изменить?

удалена мертвая ссылка ImageShack

Обновление 1: код и тестовый файл изменены

Ответы [ 7 ]

29 голосов
/ 19 ноября 2010

CharacterSet по умолчанию равен «ISO-8859-1», если он не указан в заголовке типа содержимого сервера (отличается от метатега «charset» в HTML) Я сравниваю HttpWebResponse.CharacterSet с атрибутом charset HTML. Если они разные - я использую кодировку, как указано в HTML, чтобы перечитать страницу еще раз, но на этот раз с правильной кодировкой.

См. Код:

    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();
            }
        }
    }
25 голосов
/ 23 октября 2008

Во-первых, проще написать этот код, используя StreamReader и 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();
    }
}

Тогда это просто вопрос поиска правильной кодировки. Как вы создали файл? Если это с Блокнотом, то вы, вероятно, хотите Encoding.Default - но это, очевидно, не переносимо, так как это кодировка по умолчанию для вашего ПК.

На хорошо работающем веб-сервере в ответе указывается кодировка в его заголовках. Сказав это, заголовки ответа иногда утверждают одно, а в некоторых случаях HTML требует другого.

15 голосов
/ 23 марта 2012

Если вы не хотите загружать страницу дважды, я немного изменил код Алекса, используя Как поместить WebResponse в поток памяти? . Вот результат

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;
}
3 голосов
/ 12 сентября 2016

Здесь есть несколько хороших решений, но все они, похоже, пытаются разобрать кодировку из строки типа контента. Вот решение с использованием System.Net.Mime.ContentType, которое должно быть более надежным и более коротким.

 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);
1 голос
/ 29 июля 2016

Это код, который загружается один раз.

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();
0 голосов
/ 19 декабря 2015

По-прежнему возникают проблемы при запросе веб-страницы "www.google.fr" из веб-запроса.

Я проверил необработанный запрос и ответ с помощью Fiddler. Проблема исходит от серверов Google. Заголовки HTTP ответа имеют значение charset = ISO-8859-1, сам текст кодируется с помощью ISO-8859-1, а HTML-код говорит charset = UTF-8. Это бессвязно и приводит к ошибкам кодирования.

После многих испытаний мне удалось найти обходной путь. Просто добавьте:

myHttpWebRequest.UserAgent = "Mozilla/5.0";

к вашему коду, и Google Response волшебным образом и полностью превратится в UTF-8.

0 голосов
/ 25 января 2013

Я изучил ту же проблему с помощью WireShark, отличного анализатора протоколов. Я думаю, что у класса httpWebResponse есть некоторые недостатки в дизайне. Фактически, вся сущность сообщения была загружена при первом вызове метода GetResponse () класса HttpWebRequest, но в инфраструктуре нет места для хранения данных в классе HttpWebResponse или где-то еще, в результате чего вы должны получить поток ответов. во второй раз.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...