最近在實際工作的兩個項目中都遇到了亂碼問題,雖然沒有對亂碼實際性問題有深刻理解,不過對於現象倒是有了一二的端倪觀察,現在把自己的解決思路共享一下。
我將亂碼問題歸類爲4種情況:
第一種:兩個頁面之間或者頁面與後臺之間參數傳遞,一個request請求傳遞到另一個頁面或者後臺,在接收到參數進行中文處理時,出現了亂碼。亂碼的問題出現大概也有這樣幾種情況,這種情況多見於前臺用form傳遞參數:
1)文件編碼不統一造成的,如一個頁面是gb2312,一個頁面是utf-8,甚至於有的人會在一個頁面設置兩個編碼格式;這種情況最好辦,文件編碼統一就好了。
2)瀏覽器默認的編碼格式與後臺處理編碼存在不一致。常見的瀏覽器默認處理編碼"ISO8859-1",處理起來也很簡單,基本上利用以下編程可以解決:
// 自定義字符串selfDefStr
selfDefStr = new String(selfDefStr .getBytes("ISO8859-1"), "UTF-8");
3)前兩種組合,這個實際情況發生也很多。
第二種:傳遞的url中包含參數,參數含有中文,多見於直接地址傳參,或者json格式傳遞參數,這種情況出現中文亂碼,多是由於瀏覽器版本造成的,經測試,firefox和谷歌瀏覽器傳遞中文時,只要利用前面提到的第一種2)的解碼方法即可解決,但對於ie瀏覽器,先要對ie進行編碼操作才行,通過js encode方法 ,進行16進制編碼,旨在將中文編程遺傳英文支持良好的字符,傳遞到後臺時信息不會錯亂。
String temStr= URLEncoder.encode(selfDefStr, "UTF-8");
firefox和谷歌同樣可以編碼後傳遞,這樣保證方式統一,無需判斷(注ie只在ie8以上測試過)
有的文章說在java後臺(側)需要利用java的decode方法進行解碼,經本人測試,後臺解碼反而亂碼,直接使用第一種2)的解碼方法進行處理反而通過,所以在此只告訴大家本人是如此解決的。萬一如此解決是亂碼,大家記得前臺編碼,後臺可以解碼這種方案即可。
第三種:插件給java後臺(jsp)傳遞參數,比如本人集成金格公司的網頁版電子簽章,該空間只適用於ie下使用,封裝成ocx,需要activex調用。由於參數值控件提供,無法知道正確的參數值是多少。解決方法最終是一樣的,也是如下方法,只不過要知道控件的預編碼格式,如金格是gb2312,而本人工程默認是utf-8,就不能轉成utf-8:
// 自定義字符串selfDefStr
selfDefStr = new String(selfDefStr .getBytes("ISO8859-1"), "GB2312");
這裏值得一提的是,由於本人不知道參數傳遞是什麼形式,解決方法是,利用抓包工具來查看參數,本人推薦用fidder,具體使用本人就不贅述了,可以看到request請求信息,不如頭信息,編碼格式等,不過編碼格式的信息本人認爲這種方式意義不大,它代表的是傳遞過來的頁面的編碼格式,跟控件無關,最好是詢問控件出品方編碼格式,如果聯繫不到只能猜了,但是抓包的數據還是有利於我們對於數據一致性進行明確。抓包界面如下:
可以看到左邊是每次請求,右邊是請求傳遞的參數。該值意義重大,可以多分析幾次,看看是否每次傳遞不同,窺探控件端倪。
第四種:由於統一的編碼過濾器造成的亂碼。統一過濾器的好處是對所有頁面統一中文轉碼,基本上不會出現中文亂碼的情況,但是總有例外,像第三種情況,總有一些特殊頁面參數來源不同,編碼格式不同,利用過濾器反而進行了一次過濾轉碼,造成後臺處理時,如何處理也不對,這種情況,就要排除個別頁面,不讓其轉碼。因爲這種情況往往被忽視,特別提出,共享大家。參數excludedPages(自定義)即爲排除。 web.xml
<filter>
<filter-name>SetCharacterEncoding</filter-name>
<filter-class>com.horizon.filter.encoding.SetCharacterEncodingFilter</filter-class>
<!-- 用戶請求和響應的編碼設置程序 -->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>ignore</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>excludedPages</param-name>
<param-value>/isignature/Service.jsp</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>SetCharacterEncoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
對應java方法
package com.horizon.filter.encoding;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
public class SetCharacterEncodingFilter implements Filter {
protected String encoding;
protected boolean ignore;
// 排除不進行統一編碼的頁面
protected String excludedPages;
public SetCharacterEncodingFilter() {
this.encoding = null;
this.ignore = true;
this.excludedPages = "";
}
public void init(FilterConfig filterConfig) throws ServletException {
this.encoding = filterConfig.getInitParameter("encoding");
String value = filterConfig.getInitParameter("ignore");
this.excludedPages = filterConfig.getInitParameter("excludedPages");
if (value == null)
this.ignore = true;
else if (value.equalsIgnoreCase("true"))
this.ignore = true;
else if (value.equalsIgnoreCase("yes"))
this.ignore = true;
else
this.ignore = false;
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
if ((this.ignore) || (request.getCharacterEncoding() == null)) {
if(excludedPages.indexOf(((HttpServletRequest)request).getServletPath()) == -1) {
String encoding = selectEncoding(request);
if (encoding != null) {
request.setCharacterEncoding(encoding);
}
}
}
chain.doFilter(request, response);
}
public void destroy() {
this.encoding = null;
}
protected String selectEncoding(ServletRequest request) {
return this.encoding;
}
}