全面分析Java相關(guān)的“編碼”問(wèn)題_第1頁(yè)
全面分析Java相關(guān)的“編碼”問(wèn)題_第2頁(yè)
全面分析Java相關(guān)的“編碼”問(wèn)題_第3頁(yè)
全面分析Java相關(guān)的“編碼”問(wèn)題_第4頁(yè)
全面分析Java相關(guān)的“編碼”問(wèn)題_第5頁(yè)
已閱讀5頁(yè),還剩16頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

全面分析Java相關(guān)的“編碼”問(wèn)題本文說(shuō)明Java程序員遇到的一個(gè)很頭痛的問(wèn)題就是編碼問(wèn)題。一旦開(kāi)發(fā)與系統(tǒng)平臺(tái)及網(wǎng)絡(luò)相關(guān)的程序而需要傳輸中文字符時(shí),若不能正確掌握編碼的知識(shí),將頻頻出現(xiàn)亂碼問(wèn)題而擾亂開(kāi)發(fā)計(jì)劃。目前已經(jīng)存在大量的關(guān)于編碼問(wèn)題的講解。個(gè)人覺(jué)得這些文檔主要是教“怎樣解決目前問(wèn)題”而非“為什么有這個(gè)問(wèn)題”。希望本文能夠幫助讀者從根本上了解編碼原理,以及軟件開(kāi)發(fā)過(guò)程中出現(xiàn)亂碼的原因,而非僅僅是解決某個(gè)具體問(wèn)題。字符集與編碼標(biāo)準(zhǔn)字符集UNICODE從概念上講,字符集并不完全等同與編碼標(biāo)準(zhǔn),這兩個(gè)概念的區(qū)別很模糊。(未經(jīng)過(guò)文獻(xiàn)證實(shí),只是以掌握的知識(shí)這么認(rèn)為)。大家都清楚Java使用的是UNICODE字符集。請(qǐng)注意這里使用的是“字符集”關(guān)鍵字。下面以UNICODE為例淺談字符集與編碼標(biāo)準(zhǔn)。UNICODE是一套字符集而非編碼標(biāo)準(zhǔn)。UNICODE字符集并非一直不變,目前流行使用的版本是使用2個(gè)字節(jié)來(lái)存儲(chǔ)理論數(shù)量為256x256=65535(個(gè))的字符集。兩個(gè)字節(jié)能表示的范圍也就是這個(gè)數(shù)字,以16進(jìn)制表示就是0x0000-0xFFFF。這65535(個(gè))已經(jīng)足夠收錄目前世界上主要語(yǔ)言的大多數(shù)字符了,保證日常通信是沒(méi)問(wèn)題的。最新的UNICODE標(biāo)準(zhǔn)已經(jīng)可以支持幾百萬(wàn)個(gè)字符了,當(dāng)然隨之而來(lái)的則是一個(gè)字符占用的字節(jié)數(shù)將更大。在目前使用的JRE版本中,一個(gè)中文字符是使用兩個(gè)字節(jié)的內(nèi)存空間來(lái)存儲(chǔ)的。在Java中測(cè)試UNICODE的相關(guān)功能是非常容易的:首先是查看一個(gè)中文字符的UNICODE編碼值(特別注意,這里指的是字符集中一個(gè)字符所代表的數(shù)字,它是存放在內(nèi)存中的)。運(yùn)行如下代碼將可以得到:charch1='漢';intnch1=(int)ch1;System.out.println("漢:"+Integer.toHexString(nch1));運(yùn)行結(jié)果為:漢:6c49。也就是說(shuō)“漢”這個(gè)字符在內(nèi)存中實(shí)際上是占用了兩個(gè)字節(jié)的空間,一個(gè)字節(jié)存放的是“6C”而另一個(gè)字節(jié)存放的是“49”。這個(gè)十六進(jìn)制數(shù)“0x6c49”所代表的數(shù)字則是在UNICODE字符集標(biāo)準(zhǔn)中“漢”這個(gè)字對(duì)應(yīng)的數(shù)字值。Java中提供了對(duì)“轉(zhuǎn)碼”相當(dāng)好的支持,使用的時(shí)候也非常方便。請(qǐng)運(yùn)行下面的代碼:Stringstr=“\u6c49”;System.out.println("6C49-->"+str);運(yùn)行結(jié)果:6C49-->漢?!癨U”是將十六進(jìn)制數(shù)轉(zhuǎn)化成字符的轉(zhuǎn)義字符。它只對(duì)它后面緊跟上的四個(gè)字符起作用。比如說(shuō):(‘a(chǎn)’的UNICODE數(shù)字編碼是61)Stringstr=“\u61”;//這句代碼是通不過(guò)編譯的,”\u后面至少要4位十六進(jìn)制的數(shù)字字符”Stringstr=“\ugf61”;//代碼無(wú)法通過(guò)編譯,提示不正確的UNICODE編碼。Stringstr=“\u0061”;//代碼能夠運(yùn)行,打印str的結(jié)果為”a”。在JRE的bin目錄下有一個(gè)native2ascii.exe程序,它可以提供對(duì)中文字符的轉(zhuǎn)碼,轉(zhuǎn)化成上述的\uXXXX的格式。因?yàn)檫@種格式的字符串可以在完全不支持中文的環(huán)境中存儲(chǔ)和傳輸,并且也可以被Java程序輕松的還原(Stringstr=“\u6c49”;這樣就還原了,夠簡(jiǎn)單了)。實(shí)際上手工編寫一個(gè)native2ascii.exe的功能也是很簡(jiǎn)單的,前面已經(jīng)介紹了其中的原理了。Java中UNICODE字符集是表示在內(nèi)存中的字符的編碼,是和String類緊密相關(guān)的。一旦一個(gè)字符串建立,這些字符在內(nèi)存中所存放的十六進(jìn)制數(shù)就是根據(jù)UNICODE而來(lái)。在不需要寫入文件和網(wǎng)絡(luò)傳輸?shù)那闆r下它的編碼都是統(tǒng)一的。換句話說(shuō)String類在處理字符的時(shí)候會(huì)將對(duì)象自身存儲(chǔ)的“字節(jié)數(shù)組”以UNICODE來(lái)分析,兩兩字節(jié)來(lái)讀取,將兩個(gè)字節(jié)作為一組當(dāng)成一個(gè)字符來(lái)處理。(注意這里)這種不需要轉(zhuǎn)換編碼的字符串處理過(guò)程是程序員非常希望見(jiàn)到的。但實(shí)際上Java系統(tǒng)的運(yùn)行其實(shí)到處都存在轉(zhuǎn)碼的處理。因?yàn)椴豢赡軘?shù)據(jù)只存在于內(nèi)存中吧,只在內(nèi)存中處理就沒(méi)任何意義了,用戶需要對(duì)數(shù)據(jù)進(jìn)行保存,讀取,打印,輸入等等操作,每一樣操作都是存在“轉(zhuǎn)碼”處理的,只是一般我們不會(huì)去關(guān)心,JRE已經(jīng)幫你做好了很多事。下面進(jìn)入下一個(gè)重點(diǎn)知識(shí),JRE與操作系統(tǒng)字符編碼轉(zhuǎn)換。Windows操作系統(tǒng)默認(rèn)支持的是GBK,它是一種編碼標(biāo)準(zhǔn)。GBK我沒(méi)深入研究過(guò),它肯定是一種編碼標(biāo)準(zhǔn),因?yàn)樗木幋a可以寫入文件。但是不是字符集筆者也不曾深入研究。我們不討論它的編碼原理,只需要知道它是和UNICODE不一樣的,也就是說(shuō)同一個(gè)字符在它們之間存放的十六進(jìn)制數(shù)是不一樣的。JRE運(yùn)行在WINDOWS中。我們從鍵盤輸入的字符是以windows默認(rèn)的編碼標(biāo)準(zhǔn)接收的,也就是你輸入的任何東西先是進(jìn)入到操作系統(tǒng)又才會(huì)進(jìn)入JRE。操作系統(tǒng)讀取數(shù)據(jù)的時(shí)候內(nèi)存中存放的是操作系統(tǒng)的默認(rèn)支持的編碼標(biāo)準(zhǔn)。這種編碼格式不是JRE默認(rèn)支持的。所以數(shù)據(jù)再進(jìn)入JRE的時(shí)候就需要一次轉(zhuǎn)碼。java.nio.charset.Charset.defaultCharset().name()方法可以得到當(dāng)前操作系統(tǒng)默認(rèn)使用的編碼標(biāo)準(zhǔn)。JRE與操作系統(tǒng)之間進(jìn)行數(shù)據(jù)通信時(shí),在未特別指定的情況下都以這個(gè)編碼進(jìn)行轉(zhuǎn)化,實(shí)際上就是UNICODE和這個(gè)方法返回的結(jié)果的那個(gè)編碼進(jìn)行轉(zhuǎn)換。通常情況下,當(dāng)JRE讀取控制臺(tái)輸入的字符時(shí)不需要進(jìn)行編碼指定,因?yàn)榭刂婆_(tái)接收數(shù)據(jù)后所存放的編碼不會(huì)被用戶更改,所以JRE只要用系統(tǒng)默認(rèn)的編碼進(jìn)行轉(zhuǎn)化就可以正確處理。(這個(gè)過(guò)程是:操作系統(tǒng)中存在一個(gè)字符串,它是以GBK編碼的。而JRE需要將它讀到JRE的內(nèi)存里頭,就需要通過(guò)JRE里面已經(jīng)編寫好了的GBK->UNICODE算法進(jìn)行轉(zhuǎn)化。String類中提供了轉(zhuǎn)化的方法,詳細(xì)請(qǐng)看java.lang.String類的多種構(gòu)造方法)。當(dāng)處理的是文件的時(shí)候就復(fù)雜一點(diǎn)了,因?yàn)槲募凶址木幋a并不肯定是系統(tǒng)默認(rèn)的編碼。這個(gè)時(shí)候用戶在讀取的時(shí)候可以指定某一種編碼來(lái)讀取,使用HYPERLINKF:\JAVADOC\J2SE\zh\api\java\io\InputStreamReader.html;byte[]str_utf8_bytes=str.getBytes("UTF-8");得到的str_utf8_bytes則是“漢”這個(gè)字用UTF-8編碼時(shí)的字節(jié)數(shù)組。它的值經(jīng)過(guò)測(cè)試得到結(jié)果是{-26,-79,-119}。也就是說(shuō),當(dāng)“漢”這個(gè)字以UTF-8編碼標(biāo)準(zhǔn)寫入文件時(shí),它占用了三個(gè)byte的大小,分別是-26,-79,-119。通過(guò)這三個(gè)數(shù)字組成一個(gè)字節(jié)數(shù)組,是可以還原得到一個(gè)漢字“漢”的。代碼如下:byte[]bytes_utf8=newbyte[]{-26,-79,-119};//創(chuàng)建字節(jié)數(shù)組Stringstr=newString(bytes_utf8,"UTF-8");//使用字節(jié)數(shù)組創(chuàng)建字符串,并且告訴系統(tǒng)使用“UTF-8”編碼標(biāo)準(zhǔn)類解析這個(gè)字節(jié)數(shù)組。System.out.println("字節(jié)數(shù)組{-26,-79,-119}表示漢字:"+str);輸出結(jié)果:字節(jié)數(shù)組{-26,-79,-119}表示漢字:漢。其中這三個(gè)數(shù)字都是以十進(jìn)制表示的整數(shù),如果想以十六進(jìn)制查看只需要用Integer.toHexString就可以轉(zhuǎn)化成十六進(jìn)制了,可以測(cè)試,它們與“6C”和“49”這兩個(gè)“漢”的UNICODE碼差了很遠(yuǎn)。使用同樣方法,可以分別得到“漢”這個(gè)字使用GBK編碼時(shí)所得到的字節(jié)數(shù)組Stringstr="漢";byte[]str_gbk_bytes=str.getBytes("GBK");得到的字節(jié)數(shù)組為{-70-70},結(jié)果告訴我們“漢”這個(gè)字以GBK編碼的時(shí)候產(chǎn)生了兩個(gè)字節(jié),這兩個(gè)字節(jié)分別存放的是-70和-70。同樣可以使用上面的方法還原,讀者可以自己測(cè)試。注意:\uXXXX格式是Java常用的。它這種格式轉(zhuǎn)化和這里的編碼并不是一回事。因?yàn)椴豢赡軐uXXXX直接寫入文件。寫入文件之后可能Java系統(tǒng)可以識(shí)別,但其他平臺(tái)就未必了。而使用UTF-8和GBK則可以和其他平臺(tái)進(jìn)行通信。特別強(qiáng)調(diào):同一個(gè)字使用不同的編碼得到的字節(jié)數(shù)組的值可能不一樣(這樣說(shuō)是因?yàn)橛行┚幋a之間有兼容關(guān)系,可能是一樣的),虛擬機(jī)中的字符串并不是以某種可寫入文件的編碼格式存儲(chǔ)的,而是以UNICODE值存放的。要寫入文件或者發(fā)送到網(wǎng)絡(luò)傳輸線上面都是需要進(jìn)行轉(zhuǎn)碼的,轉(zhuǎn)碼的方法就是String.getBytes()方法,給一個(gè)編碼名稱做參數(shù)就得到了該編碼下這個(gè)字符串的字節(jié)數(shù)組了。還原的時(shí)候是使用String的構(gòu)造方法,但是你必須知道這個(gè)字節(jié)數(shù)組是以哪種格式編碼的,不然系統(tǒng)不能正確讀取。剛才已經(jīng)得知{-70,-70}這個(gè)字節(jié)數(shù)組是“漢”這個(gè)字以GBK編碼時(shí)得到的字節(jié)數(shù)組。如果你使用Stringstr=newString(newbyte[]{-70,-70},”utf-8”)來(lái)還原,肯定是會(huì)出亂碼的。以上就介紹完了JRE之中關(guān)于編碼的知識(shí),也簡(jiǎn)單介紹了編碼與編碼之間的轉(zhuǎn)化。UNICODE可以作為一個(gè)中間標(biāo)準(zhǔn),因?yàn)镴RE已經(jīng)完成了UNICODE與任意編碼之間的轉(zhuǎn)換功能,這樣就可以完成不同編碼之間的轉(zhuǎn)化功能。WEB系統(tǒng)中編碼問(wèn)題的出現(xiàn)JSP頁(yè)面中設(shè)置編碼在WEB系統(tǒng)的通信模式中,出現(xiàn)編碼轉(zhuǎn)換的地方很多。瀏覽器向服務(wù)器發(fā)送一次請(qǐng)求的數(shù)據(jù)包中,就有三個(gè)地方涉及到編碼問(wèn)題。它們分別是:URL、URL后面的參數(shù)以及表單。通常情況下URL和URL后面的參數(shù)都不會(huì)出現(xiàn)中文字符,在沒(méi)有中文字符的時(shí)候是不存在亂碼問(wèn)題的,因?yàn)樗芯幋a標(biāo)準(zhǔn)中對(duì)于英文字符的碼值都是一樣的。而當(dāng)URL和URL中參數(shù)出現(xiàn)中文的時(shí)候,編碼問(wèn)題就相當(dāng)棘手。首先是URL路徑中如果出現(xiàn)中文,形如/pro/查詢.jsp的URL字符串,瀏覽器訪問(wèn)的是一個(gè)中文文件名的JSP文件“查詢.jsp”。瀏覽器在發(fā)送請(qǐng)求的時(shí)候會(huì)將路徑中的中文經(jīng)過(guò)轉(zhuǎn)碼。首先假設(shè)瀏覽器以UTF-8轉(zhuǎn)碼。“查詢”這兩個(gè)漢字得到的字節(jié)數(shù)組為{-26,-97,-91,-24,-81,-94}。這里-26是個(gè)負(fù)數(shù),并不能直接轉(zhuǎn)化成十六進(jìn)制。這其中涉及到數(shù)字編碼的問(wèn)題(原碼、反碼和補(bǔ)碼的知識(shí)是計(jì)算機(jī)組成原理中涉及的)。只需要知道,瀏覽器將這六個(gè)數(shù)字轉(zhuǎn)化成了六組十六進(jìn)制字符串,且一個(gè)字符串只有兩個(gè)字符,并且最后以“%”來(lái)連接。轉(zhuǎn)化的結(jié)果是“%E6%9F%A5%E8%AF%A2”。也就是說(shuō),轉(zhuǎn)碼之后出現(xiàn)的每一個(gè)字節(jié),都以%XX的形式表示,XX表示這個(gè)字節(jié)所代表的十六進(jìn)制數(shù)。注意一個(gè)問(wèn)題,26和-26轉(zhuǎn)化成的結(jié)果肯定是不一樣的。至于這里到底怎么轉(zhuǎn)的,需要詳細(xì)了解原碼、反碼和補(bǔ)碼的知識(shí)。以范圍來(lái)說(shuō)0x00-0xFF表示的范圍剛好是一個(gè)字節(jié)表示的范圍,而一個(gè)字節(jié)表示的整數(shù)范圍是-128到127。[-128,127]與[0x00,0xFF]是有一個(gè)對(duì)應(yīng)關(guān)系的,并且是一對(duì)一的關(guān)系。不必去深究這里是怎么轉(zhuǎn)化的,在Java中提供了現(xiàn)成的方法完成這個(gè)轉(zhuǎn)化過(guò)程,.URLEncoder.encode方法可以完成轉(zhuǎn)化。(查看附錄)關(guān)鍵的問(wèn)題是這樣的:瀏覽器發(fā)送一個(gè)請(qǐng)求的時(shí)候,一次請(qǐng)求是一個(gè)數(shù)據(jù)包。這個(gè)數(shù)據(jù)包中同時(shí)包含了訪問(wèn)的URL路徑(中文經(jīng)過(guò)轉(zhuǎn)碼),還有URL后面以“?”連接的參數(shù)(如果參數(shù)有中文也會(huì)轉(zhuǎn)碼),還加上頁(yè)面中的表單。比如如下的表單就會(huì)出現(xiàn)這個(gè)問(wèn)題<formaction=”用戶登陸.jsp?username=張三”> <input…/> <input…/><inputtype=”submit”…/></form>當(dāng)用戶輸入了中文數(shù)據(jù)點(diǎn)了提交。這一次請(qǐng)求中三個(gè)存放數(shù)據(jù)的區(qū)域都出現(xiàn)了中文。為什么會(huì)頻頻造成亂碼呢?下面將闡述:第一部分,URL路徑部分的中文以何種編碼標(biāo)準(zhǔn)進(jìn)行轉(zhuǎn)碼,并不是程序中能夠設(shè)置的。而是瀏覽器默認(rèn)的。注意!注意!這是一個(gè)嚴(yán)重的問(wèn)題,也就是說(shuō)瀏覽器無(wú)論訪問(wèn)哪個(gè)網(wǎng)址,出現(xiàn)中文的時(shí)候都是以自己“愿意”的編碼標(biāo)準(zhǔn)進(jìn)行轉(zhuǎn)碼。可以通過(guò)設(shè)置來(lái)修改瀏覽器在轉(zhuǎn)化URL路徑時(shí)使用的編碼標(biāo)準(zhǔn)。如IE的設(shè)置方式是:打開(kāi)internet選項(xiàng)。在高級(jí)里面,有一個(gè)“國(guó)際”分類,里面有一個(gè)復(fù)選框“發(fā)送UTF-8URL”。如果勾上,瀏覽器將“始終”以UTF-8進(jìn)行轉(zhuǎn)碼。如果未勾上,則會(huì)同第二部分的編碼方式一樣。不同的瀏覽器處理的方式還不一樣,值得注意!第二部分,URL路徑后面跟隨的參數(shù)部分使用的編碼方式又不一樣了,這個(gè)編碼方式是根據(jù)當(dāng)前的HTML頁(yè)面決定的。通常訪問(wèn)一個(gè)新的URL都是以表單發(fā)送或者超級(jí)鏈接,這樣前一個(gè)HTML頁(yè)面中指定的編碼方式將決定這次請(qǐng)求時(shí)參數(shù)的編碼方式。如果是首次訪問(wèn)人工輸入的URL,則瀏覽器以默認(rèn)編碼方式進(jìn)行轉(zhuǎn)碼。第三部分,表單部分瀏覽器以何種編碼方式發(fā)送數(shù)據(jù),下文將有介紹。總結(jié)來(lái)說(shuō),URL路徑部分以何種格式進(jìn)行編碼是瀏覽器自己決定的,而參數(shù)部分和表單部分同時(shí)是根據(jù)當(dāng)前頁(yè)面的語(yǔ)言環(huán)境決定的。那么是頁(yè)面的哪個(gè)設(shè)置決定了的呢?見(jiàn)如下JSP代碼:<%@pagelanguage="java"contentType="text/html;charset=utf-8"pageEncoding="gbk"%><html> <head> <metahttp-equiv="Content-Type"content="text/html;charset=utf-8"> <title>Inserttitlehere</title> </head> <body> </body></html>其中有三個(gè)設(shè)置編碼的地方,按順序分別取名A,B和C。其中A處和B是在<%@page...>中的兩個(gè)屬性,第一個(gè)是contentType="text/html;charset=utf-8",第二個(gè)是pageEncoding="gbk"。這兩個(gè)分別什么含義呢?這兩個(gè)到底哪個(gè)決定了上述的瀏覽器的編碼方式呢。答案是第一個(gè)。第一個(gè)charset=utf-8的設(shè)置,告訴瀏覽器當(dāng)前頁(yè)面使用utf-8對(duì)URL后面的參數(shù)部分進(jìn)行轉(zhuǎn)碼,并且同時(shí)以UTF-8發(fā)送表單。第二個(gè)pageEncoding="gbk"它的作用范圍并不涉及到瀏覽器。它的作用效果是決定當(dāng)前JSP文件保存到操作系統(tǒng)中以何種編碼方式編碼;并且告訴WEB服務(wù)器,在讀取到這個(gè)JSP頁(yè)面的時(shí)候該也何種編碼讀取。如果當(dāng)pageEncoding未設(shè)置的時(shí)候,系統(tǒng)會(huì)參考第一個(gè)contentType="text/html;charset=utf-8"的編碼。如果都未設(shè)置,當(dāng)頁(yè)面又有中文的時(shí)候,JSP頁(yè)面根本無(wú)法保存,不信你就試試看。第三個(gè)是HTML部分設(shè)置的編碼方式。它是告訴瀏覽器取得從服務(wù)器返回回來(lái)的字節(jié)數(shù)組時(shí),解析字節(jié)數(shù)組該使用的編碼方式。就是瀏覽器將使用這個(gè)編碼方式解析從網(wǎng)絡(luò)上取得的字節(jié)數(shù)組而轉(zhuǎn)化成HTML字符串。查看HTML文檔,其中對(duì)charset的解釋為“設(shè)置或獲取用于解碼對(duì)象的字符集”。Servlet測(cè)試代碼如下:response.setCharacterEncoding("UTF-8"); PrintWriterout=response.getWriter(); out.append("<html>"); out.append("<head>"); out.append("<metahttp-equiv=\"Content-Type\"content=\"text/html;charset=gbk\">"); out.append("<title>Inserttitlehere</title>"); out.append("</head>"); out.append("<body>"); out.append("<div>寫個(gè)漢字看看</div>"); out.append("</body>"); out.append("</html>"); out.flush(); out.close();當(dāng)response中指定的編碼方式和HTML設(shè)置的編碼方式不一樣時(shí),瀏覽器無(wú)法正確顯示數(shù)據(jù)。也就是說(shuō)WEB服務(wù)器向?yàn)g覽器發(fā)送的數(shù)據(jù)是以UTF-8編碼的,而瀏覽器讀取的時(shí)候是以GBK讀取,肯定無(wú)法正確顯示。這里又說(shuō)明一個(gè)問(wèn)題,在out.append("<metahttp-equiv=\"Content-Type\"content=\"text/html;charset=gbk\">");之前的代碼中不應(yīng)該出現(xiàn)中文,瀏覽器要讀到這里的時(shí)候才會(huì)修改自己讀取數(shù)據(jù)的方式。實(shí)際開(kāi)發(fā)中,<title>標(biāo)簽要放在<meta>標(biāo)簽之后。但是這個(gè)地方的配置只在純.html文件中起作用,或者在Servlet中未設(shè)置Response.setContentType的情況下,而在JSP中會(huì)被<%@pagecontentType="text/html;charset=utf-8">覆蓋,后面有詳細(xì)介紹。在JSP頁(yè)面中的HTML部分指定的編碼方式是無(wú)效的,因?yàn)?lt;%@pagelanguage="java"contentType="text/html;charset=utf-8"%>已經(jīng)指定了。也就是說(shuō)瀏覽器會(huì)根據(jù)這一條命令指定的編碼來(lái)讀取服務(wù)器傳回來(lái)的數(shù)據(jù),同時(shí)也指定了Servlet在發(fā)送數(shù)據(jù)的時(shí)候使用的編碼。如果筆者有興趣,可以做查相關(guān)資料。服務(wù)器返回給瀏覽器的數(shù)據(jù)中除了HTML之外還包含很多數(shù)據(jù)的header。Response.setContentType設(shè)置的數(shù)據(jù)就是存放在這些header里頭的。這一條指令在jsp轉(zhuǎn)化成java文件之后,變成了代碼“response.setContentType("text/html;charset=utf-8");”。如果這里未設(shè)置,那么瀏覽器會(huì)根據(jù)HTML里面<meta>中指定的編碼方式來(lái)解析。比如說(shuō),在一個(gè).html頁(yè)面中,肯定沒(méi)得response.setContentType。<html> <head> <metahttp-equiv="Content-Type"content="text/html;charset=utf-8"> <title>Inserttitlehere</title> </head> <body> </body></html>此時(shí)瀏覽器會(huì)使用<meta>里面配置的編碼方式來(lái)發(fā)送當(dāng)前表單和對(duì)URL進(jìn)行轉(zhuǎn)碼。如果是JSP頁(yè)面生成的HTML中的<metahttp-equiv="Content-Type"content="text/html;charset=utf-8">通常是無(wú)效的。因?yàn)闉g覽器會(huì)以response.setContentType的值為準(zhǔn),這個(gè)值是放在返回時(shí)數(shù)據(jù)包中的header中的,查看網(wǎng)頁(yè)源代碼是看不到的。那為什么還要HTML中可以指定一個(gè)編碼格式呢。這是因?yàn)镠TML還有另一個(gè)用途,它可以直接保存到操作系統(tǒng)中由瀏覽器直接讀取,而非從網(wǎng)絡(luò)上獲取。瀏覽器訪問(wèn)WEB服務(wù)器的時(shí)候,服務(wù)器返回?cái)?shù)據(jù)之前就告訴了瀏覽器該用何種編碼格式解析我發(fā)給你的數(shù)據(jù)。瀏覽器直接從操作系統(tǒng)中讀取一個(gè)HTML文件的時(shí)候就不同了,沒(méi)人告訴我。那么我就要從HTML中的<metahttp-equiv=\"Content-Type\"content=\"text/html;charset=gbk\">這段代碼去判斷。FileOutputStreamwriter=newFileOutputStream("test.html"); PrintWriterout=newPrintWriter(newOutputStreamWriter(writer,"utf-8")); out.append("<html>"); out.append("<head>"); out.append("<metahttp-equiv=\"Content-Type\"content=\"text/html;charset=gbk\">"); out.append("<title>Inserttitlehere</title>"); out.append("</head>"); out.append("<body>"); out.append("<div>寫個(gè)漢字看看</div>"); out.append("</body>"); out.append("</html>"); out.flush(); out.close();通過(guò)上面代碼測(cè)試,寫入一個(gè)HTML文件到硬盤,并且指定以u(píng)tf-8編碼格式寫入文件。然后用瀏覽器打開(kāi)這個(gè)HTML文件,使用的是GBK進(jìn)行解析,發(fā)現(xiàn)是亂碼。如果這兩個(gè)編碼是一致的,就不是亂碼了。也就是說(shuō)HTML中的編碼在這里起了作用。服務(wù)器取得參數(shù)URL的解析的時(shí)候使用的編碼方式是在配置文件中設(shè)置的。以TOMCAT為例,conf/server.xml中設(shè)置服務(wù)器解析URL的編碼方式。<Connectorport="8080"protocol="HTTP/1.1"maxThreads="150"connectionTimeout="20000"redirectPort="8443" URIEncoding="utf-8"/>最后一項(xiàng)就是告訴服務(wù)器該如何來(lái)解析瀏覽器訪問(wèn)的URL,無(wú)論是路徑部分還是參數(shù)部分都一樣。這樣就出現(xiàn)了一個(gè)問(wèn)題值得注意,瀏覽器對(duì)路徑部分和參數(shù)部分的編碼方式不一定是一樣的。而瀏覽器解析的時(shí)候又會(huì)以一種方式處理。很多中文網(wǎng)站都會(huì)將所有地方的編碼設(shè)置成GBK,在所有設(shè)置編碼格式的地方都設(shè)置GBK的情況下,有一個(gè)問(wèn)題必須避免,那就是URL路徑部分不能有中文出現(xiàn),否則出錯(cuò)。因?yàn)闉g覽器還是會(huì)以UTF-8來(lái)編碼路徑部分,以GBK編碼參數(shù)部分和頁(yè)面中的表單。而如果服務(wù)器server.xml中配置的編碼是GBK的話,服務(wù)器會(huì)用GBK來(lái)解析URL。殊不知這里是URL其實(shí)同時(shí)包含了UTF-8編碼的路徑部分和GBK編碼的參數(shù)部分。服務(wù)器獲取數(shù)據(jù)時(shí)用得最多的方法莫過(guò)于request.getParameter()了。request.setCharacterEncoding()這個(gè)方法可以設(shè)置讀取數(shù)據(jù)使用的編碼。而這個(gè)方法設(shè)置的編碼只能影響表單部分,并且只對(duì)POST方式起作用。因?yàn)镚ET方式的參數(shù)是放在URL中的。URL的解析方式是配置文件決定的。所以如果你的參數(shù)帶有中文,并且服務(wù)器配置了正確的編碼來(lái)解析URL,那么這里直接request.getParameter()的結(jié)果就是你需要的字符串,也不需要轉(zhuǎn)碼了。大家都知道,表單部分發(fā)送過(guò)來(lái)的參數(shù)是需要轉(zhuǎn)一次碼才能正確顯示的。通常都是用的這個(gè)方法request.getParameter().getBytes("ISO-8859-1");然后在將取得的字節(jié)數(shù)組作為參數(shù),使用String的構(gòu)造方法進(jìn)行轉(zhuǎn)換。比如byte[]buffer=request.getParameter(“name”).g

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論