none
HttpWebRequest 乱码问题 RRS feed

  • 问题

  • HttpGet("http://bbs.voc.com.cn/rss.php?fid=50");出现了乱码,我想就算是编码有问题也英文也是可以正常显示的,我可以用正则表达式获取到他的encoding,然后进行编码的转换。结果还是不行,求大侠帮看看,问题出在哪儿?怎么解决?

    static Regex regEncoding = new Regex("\\<\\?xml[\\s\\S]*?encoding=\"(?<encoding>[\\S]+?)\"", RegexOptions.Compiled);
            public static string HttpGet(string strUrl)
            {
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(strUrl);
                request.Method = "Get";
                request.Timeout = 0x2710;
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                string str = "";
                Encoding encoding = Encoding.UTF8;
                if ((response.CharacterSet != null) && (response.CharacterSet.Trim() != ""))
                {
                    try
                    {
                            encoding = Encoding.GetEncoding(response.CharacterSet);
                        
                    }
                    catch
                    {
                    }
                }
                using (Stream stream = response.GetResponseStream())
                {
                    int num = 0;
                    using (StreamReader reader = new StreamReader(stream, encoding))
                    {
                        str = reader.ReadToEnd();
                    }
                }
                Match m =regEncoding.Match(str);
                if(m.Success)
                {
                    string strEncoding = m.Result("${encoding}");
                    Encoding dest = Encoding.GetEncoding(strEncoding);
                    if(dest!=null&&dest!=encoding)
                    {
                        str = ConvertEncoding(str, encoding, dest);
                    }
                }
                return str;
            }
    
            public static string ConvertEncoding(string strContent,Encoding src,Encoding dest)
            {
                byte[] temp = src.GetBytes(strContent);
                byte[] temp1 = Encoding.Convert(src, dest, temp);
                string result = dest.GetString(temp1);
                return result;
            }



    • 已编辑 male110 2012年12月10日 3:20
    2012年12月10日 2:38

答案

  • @response.CharacterSet为空,会不会有这种情况?有没有什么通用的解决方法?

    是的,这个response的确为空

    要理解XmlDocument是如何编码的,比较复杂。一般情况下有中文混合的建议用Default(中文系统下)或者采用gb18050等方式编码。

    下面介绍下自动监测编码原理(反编译经过重重寻找之后发现一个DetectCode方法):

     // Stream input only: detect encoding from the first 4 bytes of the byte buffer starting at ps.bytes[ps.bytePos]
            private Encoding DetectEncoding() { 
                Debug.Assert( ps.bytes != null ); 
                Debug.Assert( ps.bytePos == 0 );
     
                if ( ps.bytesUsed < 2 ) {
                    return null;
                }
                int first2Bytes = ps.bytes[0] << 8 | ps.bytes[1]; 
                int next2Bytes = ( ps.bytesUsed >= 4 ) ? ( ps.bytes[2] << 8 | ps.bytes[3] ) : 0;
     
                switch ( first2Bytes ) { 
    #if !SILVERLIGHT // Removing USC4 encoding
                    case 0x0000: 
                        switch ( next2Bytes ) {
                            case 0xFEFF:
                                return Ucs4Encoding.UCS4_Bigendian;
                            case 0x003C: 
                                return Ucs4Encoding.UCS4_Bigendian;
                            case 0xFFFE: 
                                return Ucs4Encoding.UCS4_2143; 
                            case 0x3C00:
                                return Ucs4Encoding.UCS4_2143; 
                        }
                        break;
    #endif
                    case 0xFEFF: 
    #if SILVERLIGHT // Removing USC4 encoding
                        return Encoding.BigEndianUnicode; 
    #else 
                        if (next2Bytes == 0x0000) {
                            return Ucs4Encoding.UCS4_3412; 
                        }
                        else {
                            return Encoding.BigEndianUnicode;
                        } 
    #endif
                    case 0xFFFE: 
    #if SILVERLIGHT // Removing USC4 encoding 
                        return Encoding.Unicode;
    #else 
                        if ( next2Bytes == 0x0000 ) {
                            return Ucs4Encoding.UCS4_Littleendian;
                        }
                        else { 
                            return Encoding.Unicode;
                        } 
    #endif 
                    case 0x3C00:
    #if SILVERLIGHT // Removing USC4 encoding 
                        return Encoding.Unicode;
    #else
                        if ( next2Bytes == 0x0000 ) {
                            return Ucs4Encoding.UCS4_Littleendian; 
                        }
                        else { 
                            return Encoding.Unicode; 
                        }
    #endif 
                    case 0x003C:
    #if SILVERLIGHT // Removing USC4 encoding
                        return Encoding.BigEndianUnicode;
    #else 
                        if ( next2Bytes == 0x0000 ) {
                            return Ucs4Encoding.UCS4_3412; 
                        } 
                        else {
                            return Encoding.BigEndianUnicode; 
                        }
    #endif
                    case 0x4C6F:
                        if ( next2Bytes == 0xA794 ) { 
                            Throw( Res.Xml_UnknownEncoding, "ebcdic" );
                        } 
                        break; 
                    case 0xEFBB:
                        if ( ( next2Bytes & 0xFF00 ) == 0xBF00 ) { 
                            return new UTF8Encoding( true, true );
                        }
                        break;
                } 
                // Default encoding is ASCII (using SafeAsciiDecoder) until we read xml declaration.
                // If we set UTF8 encoding now, it will throw exceptions (=slow) when decoding non-UTF8-friendly 
                // characters after the xml declaration, which may be perfectly valid in the encoding 
                // specified in xml declaration.
                return null; 
            }

    我的博客园
    慈善点击,点击此处
    和谐拯救危机,全集下载,净化人心

    • 已标记为答案 male110 2012年12月10日 8:46
    2012年12月10日 8:22
    版主

全部回复

  • 因为你的第一个if条件根本不满足,导致强制把Encoding设置为UTF-8,但是页面并不是这个编码。

    建议使用Default(注意我粗体部分):

    namespace CSharp
    {
        using System.Threading.Tasks;
        using System.Xml.Linq;
        using System.Linq;
        using System.Data;
        using System.Net;
        using System.Text;
        using System.IO;
     
        class Program
        {
            public static void HttpGet(string strUrl)
            {
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(strUrl);
                request.Method = "Get";
                request.Timeout = 0x2710;
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                string str = "";
                Encoding encoding = Encoding.Default;
     
                if ((response.CharacterSet != null) && (response.CharacterSet.Trim() != ""))
                {
                    try
                    {
                        encoding = Encoding.GetEncoding(response.CharacterSet);
     
                    }
                    catch
                    {
                    }
                }
                using (Stream stream = response.GetResponseStream())
                {
                    using (StreamReader reader = new StreamReader(stream, encoding))
                    {
                        str = reader.ReadToEnd();
                        System.Console.WriteLine(str);
                    }
                }
     
            }
            static void Main(string[] args)
            {
                HttpGet("http://bbs.voc.com.cn/rss.php?fid=50");
            }
     
        }
    }

    我的博客园
    慈善点击,点击此处
    和谐拯救危机,全集下载,净化人心

    2012年12月10日 6:44
    版主
  • Default对这个是可以的,但如果碰到Utf8编码的呢?

    同时他的

    response.CharacterSet

    为空,会不会有这种情况?有没有什么通用的解决方法?

    比如XmlDocument直接load时,就不会是乱码,他是怎么判断的?


    2012年12月10日 6:59
  • @response.CharacterSet为空,会不会有这种情况?有没有什么通用的解决方法?

    是的,这个response的确为空

    要理解XmlDocument是如何编码的,比较复杂。一般情况下有中文混合的建议用Default(中文系统下)或者采用gb18050等方式编码。

    下面介绍下自动监测编码原理(反编译经过重重寻找之后发现一个DetectCode方法):

     // Stream input only: detect encoding from the first 4 bytes of the byte buffer starting at ps.bytes[ps.bytePos]
            private Encoding DetectEncoding() { 
                Debug.Assert( ps.bytes != null ); 
                Debug.Assert( ps.bytePos == 0 );
     
                if ( ps.bytesUsed < 2 ) {
                    return null;
                }
                int first2Bytes = ps.bytes[0] << 8 | ps.bytes[1]; 
                int next2Bytes = ( ps.bytesUsed >= 4 ) ? ( ps.bytes[2] << 8 | ps.bytes[3] ) : 0;
     
                switch ( first2Bytes ) { 
    #if !SILVERLIGHT // Removing USC4 encoding
                    case 0x0000: 
                        switch ( next2Bytes ) {
                            case 0xFEFF:
                                return Ucs4Encoding.UCS4_Bigendian;
                            case 0x003C: 
                                return Ucs4Encoding.UCS4_Bigendian;
                            case 0xFFFE: 
                                return Ucs4Encoding.UCS4_2143; 
                            case 0x3C00:
                                return Ucs4Encoding.UCS4_2143; 
                        }
                        break;
    #endif
                    case 0xFEFF: 
    #if SILVERLIGHT // Removing USC4 encoding
                        return Encoding.BigEndianUnicode; 
    #else 
                        if (next2Bytes == 0x0000) {
                            return Ucs4Encoding.UCS4_3412; 
                        }
                        else {
                            return Encoding.BigEndianUnicode;
                        } 
    #endif
                    case 0xFFFE: 
    #if SILVERLIGHT // Removing USC4 encoding 
                        return Encoding.Unicode;
    #else 
                        if ( next2Bytes == 0x0000 ) {
                            return Ucs4Encoding.UCS4_Littleendian;
                        }
                        else { 
                            return Encoding.Unicode;
                        } 
    #endif 
                    case 0x3C00:
    #if SILVERLIGHT // Removing USC4 encoding 
                        return Encoding.Unicode;
    #else
                        if ( next2Bytes == 0x0000 ) {
                            return Ucs4Encoding.UCS4_Littleendian; 
                        }
                        else { 
                            return Encoding.Unicode; 
                        }
    #endif 
                    case 0x003C:
    #if SILVERLIGHT // Removing USC4 encoding
                        return Encoding.BigEndianUnicode;
    #else 
                        if ( next2Bytes == 0x0000 ) {
                            return Ucs4Encoding.UCS4_3412; 
                        } 
                        else {
                            return Encoding.BigEndianUnicode; 
                        }
    #endif
                    case 0x4C6F:
                        if ( next2Bytes == 0xA794 ) { 
                            Throw( Res.Xml_UnknownEncoding, "ebcdic" );
                        } 
                        break; 
                    case 0xEFBB:
                        if ( ( next2Bytes & 0xFF00 ) == 0xBF00 ) { 
                            return new UTF8Encoding( true, true );
                        }
                        break;
                } 
                // Default encoding is ASCII (using SafeAsciiDecoder) until we read xml declaration.
                // If we set UTF8 encoding now, it will throw exceptions (=slow) when decoding non-UTF8-friendly 
                // characters after the xml declaration, which may be perfectly valid in the encoding 
                // specified in xml declaration.
                return null; 
            }

    我的博客园
    慈善点击,点击此处
    和谐拯救危机,全集下载,净化人心

    • 已标记为答案 male110 2012年12月10日 8:46
    2012年12月10日 8:22
    版主