JSP頁面編碼問題分析

jsp教程頁面編碼問題分析 <%@page contenttype="text/html; charset=utf-8"%> <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"> </head> <body> 中國 </body> </html> 這個頁面在為什麼在運行的時候「中國」會變成亂碼? analysis key step 對於上面問題的分析需要從整個jsp頁面請求的生命周期來看,一般的都需要經歷下面幾個階段: 1。應用伺服器根據jsp頁面生成一個java文件 2。應用伺服器調用java.exe將java文件編譯成一個servlet對應的class文件 3。用戶的瀏覽器請求jsp對應的servlet,web容器起一個線程執行servlet,將數據返回給客戶端瀏覽器 4。用戶的ie根據返回的數據,將結果顯示給用戶。 key step analysis 為了更好的了解編碼問題,我們暫時先從上面的四個環節一步步來分析,根據分析的結果,來得到最終的解決辦法。 1. 在應用伺服器根據jsp頁面生成java文件階段。

應用伺服器會將整個jsp頁面的代碼讀取出來,然後寫到一個新的java文件中,在讀文件和寫文件的時候都牽涉到一個編碼問題,這個編碼問題應用伺服器是如何解決的呢?我研究tomcat應用伺服器的源代碼,發現tomcat中有一個pageencoding參數非常重要,在parsercontroller會從jsp文件中讀出這個參數(如果沒有讀到,就從第一行的 contenttype中讀取charset),然後保存起來,如果沒有讀取到這個參數,會從jspconfig中讀出一個默認的 pageencoding參數,如果這兩個參數都沒有的設置,系統會默認成iso8859-1的編碼來讀取原來的jsp文件。 從上面的分析出,我們已經基本了解了應用伺服器讀取jsp文件的編碼方式,由於java底層都是基於unicode編碼來存儲字元的,所以在寫文件的時候,都輸出成unicode編碼的形式。 2。在jdk將java文件編譯成class文件的時候 可以利用-encoding參數指定源文件的編碼,這在手動編譯的時候非常重要,因為這決定了java虛擬機讀取java文件時採用的編碼方式,但是在web應用中這個環節我們可以忽略,因為應用伺服器可以很好的解決這個編碼。以 tomcat為例,由於生成的java文件是固定的utf-8編碼,所以tomcat也固定的採用utf-8編碼來讀取,通過瀏覽 abstractcatalinatask可以看到reader = new inputstreamreader(hconn.getinputstream(), charset);其中的charset=utf-8。所以在這個環節中應用伺服器都可以很好的把握,不會帶來編碼問題。 3. 用戶的瀏覽器請求jsp對應的servlet階段。

如果前面的環節中不會帶來編碼問題,也就是說在java虛擬機中運行的時候,能正常的獲取到「中國」,那麼在執行servlet的環節中不會「中國」始終是以unicode存儲的中國,那麼在第三個環節中需要關注的是 jspwriter如何將數據返回給客戶端瀏覽器。大家可以試驗一下,在java中如果用new string(str.getbytes("encoding"),"encoding")執行的時候,始終不會出現亂碼問題,也就是說,一個字元串可以用不同的代碼來getbytes()生成位元組數組(底層i18n.jar所作的工作,提供byte2char和char2byte的轉換)。 如果大家可以理解這一點,那麼下面大家就需要了解jspwriter輸出字元串時採用的編碼方式是什麼?通過瀏覽response.java類可以了解到 tomcat應用伺服器是根據contenttype來獲取的writer的編碼方式,也就是說,最後返回客戶端的位元組流是contenttype對應的 charset中獲取出來的位元組數組。 4. ie根據返回的數據處理顯示階段

通過前面的分析可以了解到,應用伺服器返回的「中國」是根據 contenttype中的charset來顯示的,只要ie知道該用這個編碼來接收位元組流並轉成字元串,並將用戶的瀏覽器推薦合適的編碼來查看結果,用戶就可以瀏覽到正確的「中國」兩個字。可以高興得是,目前的ie等瀏覽器正式這樣處理的。 conclusion 通過上面的分析,我們可以看到,在整個jsp頁面的編碼過程中,我們真正要解決的是jsp文件到java文件這個過程中的編碼問題,也就是pageencoding參數的設置問題。由於pageencoding參數是 servlet2.3規範中規定的參數,所以下面的方法在很多應用伺服器下面都通用,這方面的設置本人在工作中基本上得到了下面的一些方法: 1。在jsp頁面的中加上pageencoding參數,比如:<%@ page contenttype="text/html; charset=utf-8" pageencoding="gbk"%>,這樣就可以將頁面可以用ansi來存儲。也就是說當頁面存儲的編碼方式和chtenttype中的 charset不一樣的時候,可以考慮加上pageencoding參數。 2。有些應用伺服器(如weblogic),在沒有獲取到pageencoding參數的時候,不是先從charset中獲取編碼類型,而是從另外的一些配置文件,如weblogic.xml文件中加上下面的代碼: <jsp-descriptor> <jsp-param> <param-name>compilersupports</param-name> <param-value>true</param-value> </jsp-param> <jsp-param> <param-name>encoding</param-name> <param-value>gbk</param-value> </jsp-param> </jsp-descriptor> (在tomcat5x種也有類似的處理,在應用的web.xml文件中加上類似下面的配置項) </jsp-config> <jsp-property-group> <url-pattern>*.jsp</url-pattern> <el-ignored>true</el-ignored> </jsp-property-group> </jsp-config> 常用編碼方式分解

gb2312 中華人民共和國國家漢字信息交換用編碼,全稱《信息交換用漢字編碼字符集——基本集》,由國家標準總局發布,1981年5月1日實施,通行於大陸。新加坡等地也使用此編碼。,gb2312-80 是在國內計算機漢字信息技術發展初始階段制定的,其中包含了大部分常用的一、二級漢字,和 9 區的符號。該字符集是幾乎所有的中文系統和國際化的軟體都支持的中文字符集,這也是最基本的中文字符集。其編碼範圍是高位0xa1-0xfe,低位也是 0xa1-0xfe;漢字從 0xb0a1 開始,結束於 0xf7fe;大約包含6000多漢字(不包括特殊字元). gbk 是 gb2312-80 的擴展,是向上兼容的。其編碼範圍是 0x8140-0xfefe,剔除高位 0x80 的字位。其所有字元都可以一對一映射到 unicode 2.0,也就是說 java 實際上提供了 gbk 字符集的支持。這是現階段 windows 和其它一些中文操作系統的預設字符集,但並不是所有的國際化軟體都支持該字符集,感覺是他們並不完全知道 gbk 是怎麼回事。值得注意的是它不是國家標準,而只是規範。隨著 gb18030-2000國標的發布,它將在不久的將來完成它的歷史使命。 gbk編碼是中國大陸制訂的、等同於ucs的新的中文編碼擴展國家標準。容納(包含特殊字元)共22014個字元編碼 unicode 採用16位編碼體系,其字符集內容與iso10646的bmp(basic multilingual plane)相同。unicode於1992年6月通過dis(draf international standard),目前版本v2.0於1996公布,內容包含符號6811個,漢字20902個,韓文拼音11172個,造字區6400個,保留 20249個,共計65534個。 utf-8 俗稱萬國碼,致力於使用統一的編碼準則表達各國的文字。為表達更多的文字,utf-8採用2/3混編的方式。目前容納的漢字範圍小於gbk編碼。並且以3位元組的方式處理中文,帶來了兼容性的問題,原有的gbk,gb2312,gb18030編碼文件都不能正常的處理。因其變寬編碼,使編程變成變得困難和複雜,因為即使是最基本的字元處理函數也要分別檢查每一位元組,以分辨字元邊界。這就降低了處理速度,並需要複雜、易錯的代碼。 附:相關編碼方式及關係 unicode:

unicode.org制定的編碼機制, 要將全世界常用文字都函括進去.在1.0中是16位編碼, 由u+0000到u+ffff. 每個2byte碼對應一個字元; 在2.0開始拋棄了16位限制, 原來的16位作為基本位平面, 另外增加了16個位平面, 相當於20位編碼, 編碼範圍0到0x10ffff.

ucs:

iso制定的iso10646標準所定義的 universal character set, 採用4byte編碼.

unicode與ucs的關係:

iso與unicode.org是兩個不同的組織, 因此最初制定了不同的標準; 但自從unicode2.0開始, unicode採用了與iso 10646-1相同的字型檔和字碼, iso也承諾iso10646將不會給超出0x10ffff的ucs-4編碼賦值, 使得兩者保持一致.

ucs的編碼方式:

ucs-2, 與unicode的2byte編碼基本一樣. ucs-4, 4byte編碼, 目前是在ucs-2前加上2個全零的byte.

utf: unicode/ucs transformation format utf-8, 8bit編碼, ascii不作變換, 其他字元做變長編碼, 每個字元1-3 byte. 通常作為外碼. 有以下優點:* 與cpu位元組順序無關, 可以在不同平台之間交流* 容錯能力高, 任何一個位元組損壞後, 最多只會導致一個編碼碼位損失, 不會鏈鎖錯誤(如gb碼錯一個位元組就會整行亂碼) utf-16, 16bit編碼, 是變長碼, 大致相當於20位編碼, 值在0到0x10ffff之間, 基本上就是unicode編碼的實現. 它是變長碼, 與cpu字序有關, 但因為最省空間, 常作為網路傳輸的外碼.utf-16是unicode的preferred encoding. utf-32, 僅使用了unicode範圍(0到0x10ffff)的32位編碼, 相當於ucs-4的子集.

utf與unicode的關係: unicode是一個字符集, 可以看作為內碼.而utf是一種編碼方式, 它的出現是因為unicode不適宜在某些場合直接傳輸和處理. utf-16直接就是unicode編碼, 沒有變換, 但它包含了0x00在編碼內, 頭256位元組碼的第一個byte都是0x00, 在操作系統(c語言)中有特殊意義, 會引起問題. 採用utf-8編碼對unicode的直接編碼作些變換可以避免這問題, 並帶來一些優點.

推薦閱讀:

js實現頁面跳轉的幾種方法小結
真宗子平資料大集合 頁面複製
姐只是想幫老公買條內褲而已,姐打開頁面邪惡了
ASP.NET頁面——視圖狀態

TAG:編碼 | 問題 | 頁面 | 分析 |