web開發中的中文編碼問題

1、發起http請求時的字符編碼方式一般有兩種:

   1  以某種編碼直接發送字符,好比發送「飛」的gbk編碼,程序若是以Latin1(iso-8859-1)字符集去識別它,將獲得」難讀「的字符信息:"·É"javascript

        要轉換爲正常的字符須要以下處理:html

String correct = new String(word.getBytes("iso-8859-1"),"gbk");    //word爲上述的難讀的latin1字符串

 

   2  以某種編碼如GBK進行Base64編碼的轉換,如"飛"字符以GBK進行Base64轉換可得:"%B7%C9";以UTF-8進行Base64轉換得:」%E9%A3%9E「java

       要轉換爲正常的字符須要以下處理:web

 

String correct = URLDecoder.decode(word, "gbk");       //若是是utf-8轉來的則使用utf-8

 

2、而經過瀏覽器發起http請求一般有如下幾種行爲:

  1  在瀏覽器地址欄輸入地址進行訪問
  2  頁面表單的get和post提交
  3  頁面超連接
  4  ajax異步請求

其中ajax異步請求的編碼方式可由javascript控制,此處再也不討論。ajax

對於其餘的三種行爲,不一樣的瀏覽器的編碼處理方式並不一致,如下以IE和Firefox進行比較分析:瀏覽器

瀏覽器:IE8.0 和 Firefox6.0tomcat

web服務器:tomcat 6.0.18(本文的服務器都採用tomcat來描述,適用的版本是5.x、6.x)服務器

測試方式:分別以地址欄輸入、頁面超連接、表單的get/post幾種不一樣的請求行爲去訪問web服務器,經過web服務器的access_log來查看中文數據的編碼方式。異步

測試的中文請求數據:http://localhost:8083/struts/飛?word=飛(uri部分爲/struts/飛、參數部分爲word=飛)ide

html頁面:分別有GBK編碼和UTF8編碼的頁面兩個(除了頁面編碼外,其餘內容一致)

 

 

 1 <html>
 2 <head>
 3 <meta http-equiv="Content-Type" content="text/html; charset=gbk">  <!-- 指定頁面編碼 -->
 4 </head>
 5 <body>
 6 <hr/>
 7 <center>
 8   <form action="http://localhost:8083/struts/飛" method="get">     <!-- 表單get方式發起請求 -->
 9  get表單: 10   <input name="word" type="text" value="飛"/>
11   <input type="submit" value="submit"/>
12   </form>
13 <hr/>
14    <a href="http://localhost:8083/struts/飛?word=飛">頁面超連接</a>   <!-- 超連接方式發起請求-->
15 <hr/>
16  <form action="http://localhost:8083/struts/飛" method="post">       <!-- 表單post方式發起請求 -->
17  post表單: 18   <input name="input" type="text" value="飛"/>
19   <input type="submit" value="submit"/>
20   </form>
21 </center>
22 </body>
23 </html>
View Code

IE測試結果:

IE瀏覽器有一個高級選項:是否以UTF8發送URL。該選項對於請求數據的編碼有一些影響。

請求方式        access_log(開啓以UTF8發送URL的高級選項)                      access_log(不開啓...)                                          
地址欄輸入 "GET /struts/%E9%A3%9E?word=·É HTTP/1.1" 200 "GET /struts/%B7%C9?word=·É HTTP/1.1"
GBK頁面超連接        」GET /struts/%E9%A3%9E?word=·É HTTP/1.1" 200 "GET /struts/%B7%C9?word=·É HTTP/1.1" 200
GBK頁面表單GET方式          "GET /struts/%E9%A3%9E?word=%B7%C9 HTTP/1.1" 500   "GET /struts/%B7%C9?word=%B7%C9 HTTP/1.1" 500
GBK頁面表單POST方式 "POST /struts/%E9%A3%9E HTTP/1.1" 500 "POST /struts/%B7%C9 HTTP/1.1" 500
UTF8頁面超連接 "GET /struts/%E9%A3%9E?word=·É HTTP/1.1" 200 "GET /struts/%B7%C9?word=·É HTTP/1.1" 200
UTF8頁面表單GET方式 "GET /struts/%E9%A3%9E?word=%E9%A3%9E HTTP/1.1" 500 "GET /struts/%B7%C9?word=%E9%A3%9E HTTP/1.1" 500
UTF8頁面表單POST方式 "POST /struts/%E9%A3%9E HTTP/1.1" 500 "POST /struts/%B7%C9 HTTP/1.1" 500







 

Firefox測試結果:

請求方式 access_log
地址欄輸入 "GET /struts/%E9%A3%9E?word=%B7%C9 HTTP/1.1" 200       
GBK頁面超連接 "GET /struts/%E9%A3%9E?word=%B7%C9 HTTP/1.1"
GBK頁面表單GET方式 "GET /struts/%E9%A3%9E?word=%B7%C9 HTTP/1.1" 500
GBK頁面表單POST方式        "POST /struts/%E9%A3%9E HTTP/1.1" 500
UTF8頁面超連接 "GET /struts/%E9%A3%9E?word=%E9%A3%9E HTTP/1.1" 200
UTF8頁面表單GET方式 "GET /struts/%E9%A3%9E?word=%E9%A3%9E HTTP/1.1" 500
UTF8頁面表單POST方式 "POST /struts/%E9%A3%9E HTTP/1.1" 500


 

 

 

 

 

 

注:由表單POST方式發起的請求中參數數據被包含在請求的body體中,所以在access_log的uri中看不到參數部分的數據。但能夠確定表單POST行爲的編碼方式是以頁面編碼轉Base64的方式。

access_log的編碼說明

」%B7%C9「爲"飛「的GBK轉Base64形式;

%E9%A3%9E」爲"飛"的UTF-8轉Base64形式;

·É」爲「飛"的GBK編碼形式(使用Latin1字符集去識別GBK編碼所得的字符串)


結果分析:

1 IE 對於uri部分的編碼與「是否開啓UTF8發送URL」的高級選項相關,若是開啓,則一概使用UTF8轉Base64的編碼;不然使用GBK轉Base64的編碼。

        對於參數部分的編碼:

        A. 地址欄輸入與頁面超連接的處理一致,都直接使用GBK編碼直接發送;

        B. 頁面表單Get和Post,使用頁面編碼轉Base64編碼。

2 Firefox 對於uri部分的編碼一概採用UTF8轉Base64編碼的方式;

                對於參數部分的編碼:

        A. 地址欄輸入使用GBK轉Base64編碼;

        B. 頁面表單Get和Post,以及超連接都使用頁面編碼轉Base64編碼的方式。


3、web服務器端的編碼處理:

對於URI部分的編碼設置,tomcat服務器在Server.xml裏面作以下配置:

URIEncoding="UTF-8"  <!-- 該設置負責將URI部分進行反轉義,至關於調用URIDecoder.decode(uri,"utf-8") -->

 

 

對於表單POST提交(附在請求Body體中)的的參數,須要對HttpServletRequest對象進行編碼設置:

request.setCharacterEncoding("utf-8");   //負責將參數進行反轉義,至關於調用URIDecoder.decode(uri,"utf-8")
 

而對於超連接、表單Get、地址欄訪問形式提交請求的參數(附在URI中),則通常由上述的URIEncoding來肯定編碼轉義;也能夠使其與POST參數的處理一致,這須要在Server.xml作以下配置:

useBodyEncodingForURI="true"

 

 

以上所述的編碼設置都是針對某種編碼(如UTF-8)轉Base64的請求編碼的,對於直接用某種編碼發送請求參數的狀況卻無能爲力(如上面案例中IE直接用GBK編碼直接發送參數)。爲了能處理這樣的數據,須要在程序中手工轉換:

String word = request.getParameter("word"); word = new String(word.getBytes("iso-8859-1"),"gbk"); //傳輸的GBK編碼被tomcat服務器以latin1字符集進行識別,成爲latin1字符串,在URI轉義過程當中未被改變(不符合%xxx的轉義形式),因而從request對象取得的是latin1字符串,所以能夠作如此轉換。

 

 

4、採用統1、可靠的編碼方案:

        通過上面的一系列分析,得一些總結的方案:

        1   URI部分不要含有中文字符,由於IE和Firefox的轉義編碼多是不一致的。

        2   超連接參數部分不要含有中文,由於IE會直接發送GBK編碼的參數,在後臺須要另外處理,而Firefox則以頁面編碼作Base64轉義...

        3   統一頁面編碼,推薦使用UTF-8(因其更加國際化);

        4   表單Get和Post容許含有中文參數,web服務器將Get和Post參數的編碼處理設置爲一致:useBodyEncodingForURI=「true"

             此外使用過濾器(或其餘統一的方式)對HttpServletRequest對象進行編碼設置如:request.setCharacterEncoding("utf-8");

        5   以Ajax進行交互的狀況下,中文參數也使用頁面統一的編碼進行Base64轉義發送。

 

原文地址:http://blog.csdn.net/littleatp2008/article/details/6767062

相關文章
相關標籤/搜索