1. 程式人生 > >JSP編碼以及亂碼解決總結

JSP編碼以及亂碼解決總結

首先,說說JSP/Servlet中的幾個編碼的作用:

1.<%@pagepageEncoding="UTF-8" %>作用:

* 告訴JSP編譯器在將JSP檔案編譯成Servlet時使用的編碼。通常,在JSP內部定義的字串(直接在JSP中定義,而不是從瀏覽器提交的資料)出現亂碼時,很多都是由於該引數設定錯誤引起的。

例如,你的JSP檔案是以GBK為編碼儲存的 (右擊jsp-->Properties --> Text file encoding設定成與pageEncoding不一致時,就有亂碼),而在JSP中卻指定pageEncoding="UTF-8",就會引起JSP內部定義的字串為亂碼。

* 當JSP中不指定contentType引數,也不使用response.setCharacterEncoding方法時,指定對伺服器響應進行重新編碼的編碼

2.<%@pagecontentType="text/html;charset=GBK" %>response.setCharacterEncoding("UTF-8")作用:

* 指定對伺服器響應進行重新編碼的編碼,伺服器在將資料傳送到瀏覽器前,對資料進行重新編碼。

 * 瀏覽器也是根據這個引數來對其接收到的資料進行解碼,對其傳送的請求引數進行編碼(如果引數有:<%=URLEncoder.encode("測試","GBK") %>或javascript:encodeURI("測試")則以後者為準),

自己可以在IE的選單中選擇:檢視(V) --> 編碼(D)檢視得知瀏覽器的編碼(解碼)和<%@page contentType="text/html;charset=GBK" %>  response.setCharacterEncoding("UTF-8")設定的編碼是一致的。

因此:只要響應結果不是亂碼,則瀏覽器顯示結果一定不會是亂碼(伺服器對響應編碼和瀏覽器對響應解碼的編碼是一樣的)。出現亂碼的情況是:瀏覽器編碼 ---> 伺服器解碼得到的結果是亂碼 ---> 造成響應有亂碼 --> 瀏覽器顯示亂碼

3.<metahttp-equiv="Content-Type" content="text/html;charset=UTF-8">作用:

* 控制瀏覽器的以何種編碼顯示網頁的內容

* 與2中page指令設定的區別是,meta設定的是瀏覽器解釋,page設定的是服務端解釋

4.request.setCharacterEncoding("charset")作用:

* 設定對客戶端請求引數進行解碼所使用的編碼.

* 只對兩種請求引數提交方式有效:

* POST表單提交

* GET提交(url或GET表單提交), 此時要求配置

server.xml的<Connector>標籤的屬性:useBodyEncodingForURI="true"

5.request.getParameter("param")和request.getParameterValues("param")

所獲取到的引數資料都是經過伺服器解碼後的資料

接著說下發送請求到返回響應整個編碼解碼過程:

1.瀏覽器對請求編碼--> 伺服器(容器)對請求解碼 ---> 伺服器對響應編碼 ---> 瀏覽器對響應解碼

瀏覽器編碼 ---> 容器解碼

瀏覽器編碼預設是使用response.setCharacterEncoding—contentType—pageEncoding的優先順序指定的編碼的,但當對某些引數使用<%=URLEncoder.encode("測試","GBK") %>或javascript:encodeURI("測試")來對引數編碼時,會覆蓋預設編碼,即瀏覽器這些特定的引數編碼以<%=URLEncoder.encode("測試","GBK") %>或javascript:encodeURI("測試")為準

注意:javascript的編碼方式:encodeURI(..)和encodeURIComponent(..)是對其引數進行UTF-8編碼的

2.瀏覽器最終顯示響應結果出現亂碼是因為在過程:

瀏覽器對請求編碼 --> 伺服器(容器)對請求解碼,出現亂碼。

原因是:伺服器對響應編碼和瀏覽器對響應解碼所使用的編碼都是相同的,為response.setCharacterEncoding—contentType指定的編碼,而瀏覽器對請求引數的編碼 和 伺服器對請求引數解碼 所使用的編碼如果不一致,就會造成亂碼

3.對中文解碼,無論使用什麼解碼方式都是中文。中文只有經過編碼,再解碼才會出現亂碼的可能,如果起始編碼和末尾解碼所使用的編碼一致,就不會出現亂碼

4.瀏覽器編解碼說明:

瀏覽器在接收或傳送資料時,會對URL和引數會進行URL解碼(接收)或編碼(傳送),所使用的編碼為:<%@pagecontentType="text/html;charset=GBK" %>或response.setCharacterEncoding("UTF-8")指定的編碼

5.伺服器編解碼說明:

* 伺服器傳送資料時,按照response.setCharacterEncoding—contentType—pageEncoding的優先順序,對要傳送的資料進行編碼。

* 伺服器接收資料,要分三種情況。一種是瀏覽器直接用URL提交的資料,另外兩種是用表單的GET和POST方式提交的資料

(1)表單中POST方式提交的情況:

可以通過request.setCharacterEncoding(charset),來設定對瀏覽器提交的資料使用什麼樣的編碼進行解碼。如果不設定時,伺服器預設使用ISO-8859-1來解碼請求引數。如果頁面的contentType="GBK", 此時要想得到正確的結果,則:

Stringname = newString(request.getParameter("name").getBytes("ISO-8859-1"),"GBK");

如果設定:request.setCharacterEncoding("GBK"),則只需:String name = request .getParameter("name");

所以對於POST表單提交的資料,在獲得資料的JSP頁面中request.setCharacterEncoding要和生成提交該表單的JSP頁面的response.setCharacterEncoding設定成相同的值。還有一種方法解決POST提交亂碼問題:使用過濾器,在過濾器中設定request.setCharacterEncoding(charset)

(2)URL提交的資料和表單中GET方式提交的情況:

此時設定request.setCharacterEncoding引數是不行的,因為在Tomcat5.0中,預設情況下使用ISO-8859-1對URL提交的資料和表單中GET方式提交的資料進行解碼,而不使用該引數對URL提交的資料和表單中GET方式提交的資料解碼。要解決該問題,應該在Tomcat的配置檔案server.xml的Connector標籤中設定useBodyEncodingForURI或者URIEncoding屬性,

*useBodyEncodingForURI引數為true時表示用request.setCharacterEncoding引數對URL提交的資料和表單中GET方式提交的資料進行重新解碼。

*URIEncoding引數指定對所有GET方式請求(包括URL提交的資料和表單中GET方式提交的資料)進行統一解碼的編碼

即處理get方式請求引數有四種情況:

* 不設定server.xml的Connector標籤,此時伺服器統一對get方式的請求引數進行ISO-8859-1解碼,此時設定request.setCharacterEncoding(charset)是無效的

* 設定server.xml的Connector標籤,令useBodyEncodingForURI="true",此時使用情況和post提交方式一致

* 設定server.xml的Connector標籤,令URIEncoding="charset",此時伺服器統一對get方式的請求引數進行charset解碼

* 設定server.xml的Connector標籤,令useBodyEncodingForURI="true"URIEncoding="charset", 此時URIEncoding設定無效

<Connectorport="8080" maxThreads="150" minSpareThreads="25"maxSpareThreads="75" enableLookups="false"

redirectPort="8443"acceptCount="100" debug="0"connectionTimeout="20000" disableUploadTimeout="true"

useBodyEncodingForURI="true"URIEncoding="UTF-8"/>

範例:URLDecoder.decode(..)是伺服器端解碼的,而encodeURI(..)是js在客戶端編碼的

1. javascrip對於get方式的引數編碼: Java程式碼:url=encodeURI(url);伺服器端獲取引數後解碼: Java程式碼

Stringlinename = newString(request.getParameter("name").getBytes("ISO-8859-1"),"UTF-8");

說明:此時並沒有對server.xml的<Connector>配置useBodyEncodingForURI和URIEncoding屬性

編碼過程:瀏覽器編碼(UTF-8)--> 伺服器解碼(ISO-8859-1) --> String.getBytes方法編碼(ISO-8859-1)--> 建立String解碼(UTF-8)

2.javascript:url=encodeURI(encodeURI(url)); //用了2次encodeURI伺服器端獲取: Java程式碼

Stringlinename = request.getParameter(name); //java : 字元解碼linename =java.net.URLDecoder.decode(linename , "UTF-8");

瀏覽器編碼(UTF-8) --> 瀏覽器編碼(UTF-8)--> 伺服器解碼(ISO-8859-1) --> URLDecoder解碼(UTF-8)

3.jsp對於get方式的引數編碼:url="...."?sport=<%=URLEncoder.encoder("籃球","UTF-8") %>

伺服器端獲取引數後解碼: Java程式碼

Stringlinename = newString(request.getParameter("name").getBytes("ISO-8859-1"),"UTF-8");

說明:此時並沒有對server.xml的<Connector>配置useBodyEncodingForURI和URIEncoding屬性

編碼過程:瀏覽器編碼(UTF-8)--> 伺服器解碼(ISO-8859-1) --> String.getBytes方法編碼(ISO-8859-1)--> 建立String解碼(UTF-8)

對範例2的說明:

可能大家都覺得對中文進行兩次UTF-8編碼後,進行一次ISO-8859-1解碼和一次UTF-8解碼,為什麼得到的不是亂碼呢?

個人認為java提供的URLEncoder和URLdecoder內部是做了某些處理的,和通String.getBytes獲取位元組陣列,再newString(bytes[], charset)編解碼方式使不一樣的。如java程式碼:

String str = "漢字test";
            String str1 = URLEncoder.encode(str, "UTF-8");
            String str2 = URLEncoder.encode(str, "ISO-8859-1");
            String str3 = URLEncoder.encode(str, "UTF-8");
            String str4 = URLEncoder.encode(str3, "ISO-8859-1");
            //使用UTF-8編碼  解碼成功
            String str6 = URLDecoder.decode(str1, "UTF-8");
            //使用ISO-8859-1編碼  解碼失敗
            String str7 = URLDecoder.decode(str2, "ISO-8859-1");
            //編碼次數為兩次,解碼一次,解碼失敗
            String str8 = URLDecoder.decode(str4, "UTF-8");
            //編碼次數等於解碼次數,且最終解碼方式為字串初始編碼方式就能解碼成功,
            //即使中間編碼方式為ISO-8859-1
            String str9 = URLDecoder.decode(str8, "UTF-8");

從執行結果分析,個人覺得URLEncoder和URLDecoder對ASCII內的字元進行編碼, 無論URLEncoder.encode的charset引數是什麼,

得到的編碼結果都是一樣的,無論URLDecoder.decode的charset引數是什麼,得到的解碼結果都一樣,只要中文的起始編碼charset和最後解碼的chaset一致(這裡都是UTF-8),中間編碼和解碼次數對等(這裡均為兩次), 則得到的結果就不會亂碼。