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
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>
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編碼的方式。
對於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字符串,所以能夠作如此轉換。
通過上面的一系列分析,得一些總結的方案:
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