亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

基于字符集、字符編碼與HTTP編碼解碼之萬(wàn)象詳解

 更新時(shí)間:2013年04月23日 09:17:34   作者:  
本篇文章小編為大家介紹,基于字符集、字符編碼與HTTP編碼解碼之萬(wàn)象詳解。需要的朋友參考下

在日常編寫(xiě)代碼過(guò)程中,常常會(huì)碰到亂碼問(wèn)題,一個(gè)典型的情況是瀏覽網(wǎng)頁(yè),如果網(wǎng)站開(kāi)發(fā)者缺少經(jīng)驗(yàn),就會(huì)帶來(lái)這種令人頭疼的問(wèn)題。要了解亂碼的癥結(jié),我們就得從字符集和字符編碼說(shuō)起,先來(lái)看看它們到底是什么:
1:字符集:是一個(gè)系統(tǒng)支持的所有抽象字符的集合。字符是各種文字和符號(hào)的總稱,包括各國(guó)家文字、標(biāo)點(diǎn)符號(hào)、圖形符號(hào)、數(shù)字等。
2:字符編碼:是一套法則,最常規(guī)的理解就是:讓程序根據(jù)這個(gè)法則對(duì)應(yīng)到相應(yīng)的字符集中將byte[]存取為string。
現(xiàn)在,我們要來(lái)看看這些東西在 .NET 中對(duì)應(yīng)的是什么。

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

復(fù)制代碼 代碼如下:

foreach (var item in Encoding.GetEncodings())
{
    Console.WriteLine(item.Name);
}

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

示例:

復(fù)制代碼 代碼如下:

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

觀察Encoding類,實(shí)際上象上面UTF8這樣的屬性,只有幾個(gè),這些是最常用的字符集,要獲取其它,如gb2312這樣的字符集,則需要象如下這樣來(lái)獲得:
復(fù)制代碼 代碼如下:

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

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

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

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


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

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

復(fù)制代碼 代碼如下:

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

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

復(fù)制代碼 代碼如下:

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

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

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


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

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

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

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

2.4 為什么還是有亂碼問(wèn)題?BOM能解決一切?

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

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

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

復(fù)制代碼 代碼如下:

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

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

BOM(byte-order mark),即字節(jié)順序標(biāo)記,它是插入到以UTF-8、UTF16或UTF-32編碼Unicode文件開(kāi)頭的特殊標(biāo)記,用來(lái)識(shí)別Unicode文件的編 碼類型。對(duì)于UTF-8來(lái)說(shuō),BOM并不是必須的,因?yàn)锽OM用來(lái)標(biāo)記多字節(jié)編碼文件的編碼類型和字節(jié)順序(big-endian或little- endian)。

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


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


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

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

相關(guān)文章

  • C#?DateTime.Now.ToString()?用法示例講解

    C#?DateTime.Now.ToString()?用法示例講解

    這篇文章主要介紹了C#?DateTime.Now.ToString()?用法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2024-01-01
  • unity與vue交互(無(wú)第三方插件)

    unity與vue交互(無(wú)第三方插件)

    這篇文章主要講述了如何使用vue在通過(guò)不是用第三方插件的情況下與Unity進(jìn)行交互,該篇包含詳細(xì)的圖文講解,內(nèi)容比較詳細(xì),希望對(duì)你有所幫助
    2021-06-06
  • C#窗體控件DataGridView常用設(shè)置

    C#窗體控件DataGridView常用設(shè)置

    這篇文章主要為大家詳細(xì)介紹了C#窗體控件DataGridView常用10項(xiàng)設(shè)置,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • C# 通過(guò)反射初探ORM框架的實(shí)現(xiàn)原理(詳解)

    C# 通過(guò)反射初探ORM框架的實(shí)現(xiàn)原理(詳解)

    下面小編就為大家分享一篇C# 通過(guò)反射初探ORM框架的實(shí)現(xiàn)原理詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2017-12-12
  • C#使用foreach語(yǔ)句遍歷二維數(shù)組的方法

    C#使用foreach語(yǔ)句遍歷二維數(shù)組的方法

    這篇文章主要介紹了C#使用foreach語(yǔ)句遍歷二維數(shù)組的方法,實(shí)例分析了C#遍歷數(shù)組的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-04-04
  • C#處理猜拳問(wèn)題的簡(jiǎn)單實(shí)例(非窗體)

    C#處理猜拳問(wèn)題的簡(jiǎn)單實(shí)例(非窗體)

    下面小編就為大家?guī)?lái)一篇C#處理猜拳問(wèn)題的簡(jiǎn)單實(shí)例(非窗體)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-07-07
  • C#獲取App.Config配置項(xiàng)的方法總結(jié)

    C#獲取App.Config配置項(xiàng)的方法總結(jié)

    在本篇內(nèi)容里小編給大家分享了C#獲取App.Config配置項(xiàng)的方法和相關(guān)知識(shí)點(diǎn),需要的朋友們學(xué)習(xí)下。
    2019-03-03
  • winform模擬鼠標(biāo)按鍵的具體實(shí)現(xiàn)

    winform模擬鼠標(biāo)按鍵的具體實(shí)現(xiàn)

    這篇文章介紹了winform模擬鼠標(biāo)按鍵的具體實(shí)現(xiàn),有需要的朋友可以參考一下
    2013-10-10
  • unity實(shí)現(xiàn)延遲回調(diào)工具

    unity實(shí)現(xiàn)延遲回調(diào)工具

    這篇文章主要為大家詳細(xì)介紹了unity實(shí)現(xiàn)延遲回調(diào)工具,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • C#中常用的正則表達(dá)式實(shí)例

    C#中常用的正則表達(dá)式實(shí)例

    正則表達(dá)式在程序設(shè)計(jì)中有著重要的位置,它經(jīng)常被用于處理字符串信息,下面是C#中常用的正則表達(dá)式實(shí)例,感興趣的朋友一起看看吧
    2016-10-10

最新評(píng)論