日本好好热aⅴ|国产99视频精品免费观看|日本成人aV在线|久热香蕉国产在线

  • <cite id="ikgdy"><table id="ikgdy"></table></cite>
    1. 西西軟件下載最安全的下載網(wǎng)站、值得信賴的軟件下載站!

      首頁編程開發(fā)C#.NET → .NET 支持的字符集、字符編碼與HTTP編碼解碼

      .NET 支持的字符集、字符編碼與HTTP編碼解碼

      相關(guān)軟件相關(guān)文章發(fā)表評論 來源:西西整理時間:2013/4/23 8:37:38字體大。A-A+

      作者:西西點擊:0次評論:0次標(biāo)簽: 字符編碼

      • 類型:文件處理大小:76KB語言:中文 評分:5.0
      • 標(biāo)簽:
      立即下載

      在日常編寫代碼過程中,常常會碰到亂碼問題,一個典型的情況是瀏覽網(wǎng)頁,如果網(wǎng)站開發(fā)者缺少經(jīng)驗,就會帶來這種令人頭疼的問題。

      要了解亂碼的癥結(jié),我們就得從字符集和字符編碼說起,先來看看它們到底是什么: 
      1:字符集:是一個系統(tǒng)支持的所有抽象字符的集合。字符是各種文字和符號的總稱,包括各國家文字、標(biāo)點符號、圖形符號、數(shù)字等。 
      2:字符編碼:是一套法則,最常規(guī)的理解就是:讓程序根據(jù)這個法則對應(yīng)到相應(yīng)的字符集中將byte[]存取為string。 
      現(xiàn)在,我們要來看看這些東西在 .NET 中對應(yīng)的是什么。

      一:字符集和字符編碼 
      如果想得到全部的字符集,則使用 System.Text.Encoding.GetEncodings() 方法,以下代碼用于列出.Net支持的全部字符集:

      foreach (var item in Encoding.GetEncodings()) 

          Console.WriteLine(item.Name); 
      }

      字符串在進(jìn)行如網(wǎng)絡(luò)傳輸?shù)葓鼍皶r,要先轉(zhuǎn)為 byte[] 。但是,首先,不同的字符編碼規(guī)則,所轉(zhuǎn)換生成的byte[]是不一樣的。所以,再將byte[]轉(zhuǎn)換回string的時候,要依據(jù)原先的字符編碼規(guī)則。有如下幾種情況能導(dǎo)致“亂碼”的產(chǎn)生: 
      1:string to byte[] 和 byte[] to string,使用了不同的字符編碼規(guī)則; 
      2:byte[] to string 的 時候,當(dāng)前宿主環(huán)境沒有對應(yīng)的字符集;

      示例:

      string originalString = "Hello test, 測試!"; 
      byte[] utf8Bytes = Encoding.UTF8.GetBytes(originalString); 
      string utf8String = Encoding.UTF8.GetString(utf8Bytes); 
      string errorString = Encoding.ASCII.GetString(utf8Bytes);

      觀察Encoding類,實際上象上面UTF8這樣的屬性,只有幾個,這些是最常用的字符集,要獲取其它,如gb2312這樣的字符集,則需要象如下這樣來獲得:

      byte[] gbBytes = Encoding.GetEncoding("gb2312").GetBytes(originalString); 
      string utf8String = Encoding.GetEncoding("gb2312").GetString(gbBytes);

      二:典型應(yīng)用場景之 HttpWebResponse

      很多人都作過頁面抓取功能, HttpWebResponse 就會比較熟悉,當(dāng)然如果不嫌麻煩,也可以用 Socket 實現(xiàn),但是同時要解析很多屬性以及處理象重定向之類的諸多問題。

      2.1 http header 和http content是什么? 
      瀏覽一個網(wǎng)頁,使用很多工具,或者使用.Net中的某些類進(jìn)行抓取,都給我們結(jié)構(gòu)化為 Http 頭和正文這樣的信息,其實,當(dāng)我們發(fā)送一個請求,服務(wù)器返回給我們的是一串 byte[],我們完全可以自己去從這串 byte[] 解析出 http header 和 http content,它們之間其實僅僅非常簡單的以兩個 /r/n/ 分割開而已,歷史上有著名的CRLF攻擊,CR就是\r,LF就是\n,就利用的是這個規(guī)則。

      2.2 我們?nèi)绾尾炜磆ttp header,http content? 
      其實很簡單,既然這些都是 byte[] ,所以,我們只要知道這段 byte[] 正確的字符編碼規(guī)則,就能得到我們所需要看到的 html (html就是字符串而已)。使用 HttpWebResponse 這個類,就能請求一個 url ,該類自動為我們解析出了 httpheader ,有意思的是,它沒有給我們解析出 content ,所以,我們需要自己完成正文的byte[] to string。

      2.3 http content to string的具體做法 
      好的,實際上,httpheader  中已經(jīng)告訴了我們一些字符集編碼相關(guān)的信息,我們可能感興趣,以及會混淆的這些http頭如下:

      Content-Type:WEB 服務(wù)器告訴瀏覽器自己響應(yīng)的對象的類型和字符集。例如:Content-Type: text/html; charset='gb2312' ; 
      Content-Encoding:WEB 服務(wù)器表明自己使用了什么壓縮方法(gzip,deflate)壓縮響應(yīng)中的對象。例如:Content-Encoding:gzip 。這里我要多說一點,這個 Content-Encoding 的 Http header 會令人混淆,極度容易讓人理解成是字符集或字符編碼信息;

      那么,這些 Http 頭在HttpWebResponse 中是怎么代表的呢?

      HttpWebResponse.Content-Type對應(yīng)的是Http頭的Content-Type比如"text/html;"后的那個Charset,實際是和HttpWebResponse.Charaterset是一致的。但是如果前者無,則后者

      一般會指定一個默認(rèn)的HttpWebResponse.Charaterset,默認(rèn)為"iso-8859-1"。 
      HttpWebResponse.ContentEncoding 代表的是 http頭中 Content-Encoding,與此類似的,還有一個http頭,為Transfer-Encoding。注意,很惡心的一點是

      HttpResponse.ContentEncoding跟HttpWebResponse.ContentEncoding代表的不是一個東西,它和HttpResponse.Charaterset在MSDN上是一致的解釋。

      根據(jù)上面的說法,似乎下面的代碼就能得到http content的字符編碼規(guī)則:

      return Encoding.GetEncoding( 
         string.IsNullOrEmpty(HttpWebResponse.Charaterset) ? 
      "iso-8859-1" : HttpWebResponse.Charaterset

      但是,這里有一個很重要的但是,如果你嘗試從Http頭或者HttpWebResponse所給我的這些字符編碼信息或?qū)傩匀ソ獯a正文content的話,很可能馬上就會迎來一個大大的挫折。我們很可能會發(fā)現(xiàn)以下幾個可悲的事實:

      1:http頭的Content-Type中沒有charset信息; 
      2:HttpWebResponse.Charaterset是空的; 
      3:http頭的Content-Type和HttpWebResponse.Charaterset是不一致的; 
      4:http頭的Content-Type和HttpWebResponse.Charaterset是一致的,但是解碼還是錯的; 
      5:嘗試用"iso-8859-1"解碼也是錯的。

      2.4 為什么還是有亂碼問題?BOM能解決一切?

      之所以碰到以上問題,其實僅僅是因為,服務(wù)器給我們傳回來的是byte[],而任何程序員在寫服務(wù)器端WEB程序的時候,都有可能有意或無意的轉(zhuǎn)碼出不規(guī)范的byte[]來。所以,如果我們嘗試從http頭的Content-Type和HttpWebResponse.Charaterset想要得到編碼規(guī)則,我們就敗了,我們敗在了有標(biāo)準(zhǔn),但是沒人嚴(yán)格去執(zhí)行標(biāo)準(zhǔn)。

      有一些頗具迷惑性的API試圖在告訴我們,使用我你就能得到該流正確的Encoding了,比如,StreamReader.CurrentEncoding,我們可以把HttpWebResponse的GetResponse中讀取到

      byte[],放置到MemoryStream中,然后利用如下代碼:

      StreamReader sr = new StreamReader(memoryStream, true) 
      return sr.CurrentEncoding;

      似乎就可以得到Encoding了,其實非也,注意StreamReader構(gòu)造器的第二個參數(shù),為detectEncodingFromByteOrderMarks。ByteOrderMarks是什么呢?解釋如下:

      BOM(byte-order mark),即字節(jié)順序標(biāo)記,它是插入到以UTF-8、UTF16或UTF-32編碼Unicode文件開頭的特殊標(biāo)記,用來識別Unicode文件的編 碼類型。對于UTF-8來說,BOM并不是必須的,因為BOM用來標(biāo)記多字節(jié)編碼文件的編碼類型和字節(jié)順序(big-endian或little- endian)。

      這表明了什么呢?表明了如果你的字節(jié)流未含有BOM,或者即便包含了BOM,但是字節(jié)流不是unicode-based的Encoding,則依舊不能得到正確的Encoding,具體我們也可以看StreamReader的源碼來得到驗證。這個萬惡的CurrentEncoding屬性并沒有告訴你它的前提條件。

      2.5 關(guān)于本例的一點補充 
      以上字節(jié)流的編碼解碼,很多地方用了Response做例子,但是,以上解碼針對的是非壓縮的Response,如果服務(wù)器已經(jīng)對http流進(jìn)行了壓縮(其壓縮格式在Content-Encoding中指明了),我們就得先解壓縮,再解碼Response流,然后再解碼正文。考慮到本文的主題,特意剪裁了對于 Response 流的解壓過程。

      2.6 關(guān)于正確解碼的嘗試

      有很多人嘗試從byte[]本身去解析和判斷編碼規(guī)則的API,如:codeproject上也有相關(guān)的文章,但是可悲的事實是:并沒有一種完美的方法來自動判斷byte[]的編碼規(guī)則。還記得我們的瀏覽器(如IE)的編碼設(shè)置中的“自動選擇”嗎,其實這個自動選擇的錯誤率還是蠻高的。所以,對于字節(jié)流的生成者,如BS程序開發(fā)者,可以通過規(guī)范輸出:聲明charset和編碼規(guī)范的方式,這樣才能讓解析者(如瀏覽器)解析的時候盡可能的少出現(xiàn)亂碼。

        相關(guān)評論

        閱讀本文后您有什么感想? 已有人給出評價!

        • 8 喜歡喜歡
        • 3 頂
        • 1 難過難過
        • 5 囧
        • 3 圍觀圍觀
        • 2 無聊無聊

        熱門評論

        最新評論

        發(fā)表評論 查看所有評論(0)

        昵稱:
        表情: 高興 可 汗 我不要 害羞 好 下下下 送花 屎 親親
        字?jǐn)?shù): 0/500 (您的評論需要經(jīng)過審核才能顯示)