剛纔回顧以前的項目時,突然發現了這個老朋友,剛入坑時,這個問題可是折磨了我許久,因爲剛進公司時,負責一個GBK編碼的老項目改造,出現了不少亂碼問題,藉此機會總結一下,若也能給新入坑的夥伴一絲幫助那就更好了~:)。
問題背景
- request亂碼指的是:瀏覽器向服務器發送的請求參數中包含中文字符,服務器獲取到的請求參數的值是亂碼;
- response亂碼指的是:服務器向瀏覽器發送的數據包含中文字符,瀏覽器中顯示的是亂碼;
原因分析
不管是request亂碼還是response亂碼,其實都是由於客戶端(瀏覽器)跟服務器端採用的編碼格式不一致造成的。
- request亂碼:瀏覽器向服務器發送請求,因爲瀏覽器與服務器之間的通信實質上是socket流,所以要先將請求參數(字符)轉換成字節,也就是編碼過程,服務器接收到請求參數後進行解碼(字節轉字符),然後封裝到request對象中。如果客戶端的編碼與服務器端的解碼不統一,就會導致通過request獲取到的請求參數的值是亂碼。
- response亂碼:服務器發給瀏覽器的數據默認是按照ISO-8859-1編碼,瀏覽器接收到數據後按照默認的字符集進行解碼後顯示,如果瀏覽器的默認解碼字符集不是ISO-8859-1,就出現亂碼。
推薦方式
若準備建一個新項目,那麼web應用所有文件推薦都一致採用UTF-8編碼,通過配置編碼過濾器(見方法一)以及設置應用服務器請求編碼都爲UTF-8(見方法二中解決get請求亂碼部分), 可以有效避免出現亂碼問題。
解決方法
方法一:配置編碼過濾器
spring項目可以如下配置:
在web.xml中配置:org.springframework.web.filter.CharacterEncodingFilter
<filter>
<filter-name>encodingFilter </filter-name>
<filter-class>
org.springframework.web.filter.CharacterEncodingFilter
</filter-class>
<init-param>
<param-name>encoding </param-name>
<param-value>UTF-8 </param-value>
</init-param>
<init-param>
<param-name>forceEncoding </param-name>
<param-value>true </param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter </filter-name>
<url-pattern>*.do </url-pattern>
</filter-mapping>
方法二:設置 request 和 response 的編碼 ( 頁面編碼必須爲 utf-8 )
解決post請求亂碼:
Action中:
request.setCharacterEncoding("UTF-8");//設置傳值編碼,解決request亂碼,即解決後臺接收參數亂碼
response.setContentType("text/html;charset=UTF-8");//設置傳輸編碼,解決response亂碼,即解決頁面顯示亂碼
該方法必須在response.getWriter()之前進行設置,等同於:
response.setHeader("contentType", "text/html; charset=utf-8”);
它其實會覆蓋response.setCharacterEncoding("utf-8”)
解決get請求亂碼:
URL中的字符串的編碼和解碼是由瀏覽器和應用服務器的配置決定的,get方式提交的參數會跟在請求行中的uri後邊,服務器按照默認的iso-8859-1進行解碼,我們的程序不能設置,不要期望用request.setCharacterEncoding()方法能設置URL中參數值解碼時的字符集,但我們可以通過修改服務器端對uri參數的默認編碼來解決get請求(url傳參)的亂碼問題:
(1)對於Tomcat:
在server.xml中,設置元素的屬性URIEncoding="UTF-8”即可,作用是告訴服務器servlet解碼URL時採用的編碼。
<Connector port="8080" protocol="HTTP/1.1"
maxThreads="150" connectionTimeout="20000"
redirectPort="8443" URIEncoding="UTF-8"/>
其實還可以同時設置元素的屬性useBodyEncodingForURI=“true”,意思是請求體和uri使用相同的編碼格式。
<Connector port="8080" ... useBodyEncodingForURI="true" />
通過設置這兩個屬性,既可以解決get方式的亂碼,又可以解決 post方式的亂碼。
注意:通過修改server.xml指定服務器對get和post統一按照utf-8解碼,要求tomcat管理下的所有web應用都要使用utf-8編碼,即所有的jsp、html頁面都使用utf-8編碼。
(2)對於 weblogic服務器
在weblogic.xml中設置:
<input-charset>
<java-charset-name>GBK</java-charset-name>
</input-charset>
方法三:轉碼UTF-8(只適合解決少量棘手問題)
Action中:
String ss=new String(param.getBytes("ISO-8859-1"),"utf-8"); //轉碼爲UTF-8,其中param是前臺傳來的字符串參數,
方法四:encodeURI()兩次編碼後臺解碼(只適合解決少量棘手問題)
1、在javascript中利用encodeURI()兩次嵌套對URL中的中文參數進行編碼
2、在後臺獲取到進過前端encodeURI()編碼後的字符串,使用decode(String str,String ecn)方法進行解碼
實例:
jsp中傳參:
"param="+encodeURI(encodeURI(param))
Action接收參數:
param=java.net.URLDecoder.decode((String) getParameter("param"), "UTF-8");
參考文獻
http://www.iteye.com/problems/42143
http://blog.csdn.net/yzhz