tomcat字元集與中文亂碼的解決

來源:互聯網
上載者:User

如果你搞Java web,相信你一定遇到過亂碼問題!

通常,你是否是這樣處理中文傳參的呢?

前台:

url=encodeURI(url);

後台:

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

頁面:一通UTF-8或GB2312設定編碼。

tomcat:統一UTF-8.

然後部署測試發現,亂碼啊,你怎麼還在糾纏著我!我又不是唐僧,身上更沒肉!

亂碼問題,是個臭蟲!很臭的臭蟲!我也遇到過多次,每次都是很糾結,每次都是經過一番轉換,然後信誓旦旦地告訴自己和同事,這個亂碼我給解決了!有一天,在郵箱裡發現測試部提交了一個BUG,說日誌裡怎麼全部是亂碼~~~這時候同事們都朝我望過來,我只能滿臉黑線|||

最近閑暇下來,看了一些文章,也總結了一些,這裡還是比較推崇下面要貼的內容(因為主體還是別人的內容,暫且標為轉帖更確切!)。我不清楚亂碼問題是否已經根除了,但是我知道現在2輪測試的過程中,再也沒有了亂碼的蹤影,也許她真得消失了?!!我不知道。

好吧,進入內容吧:

=========================================咯咯================================

使用 tomcat 時,相信大家都回遇到中文亂碼的問題,具體表現為
1)通過表單取得的中文資料為亂碼
2)頁面提交中文資料,伺服器端接收為亂碼
 
一、初級解決方案 
通過一番檢索後,許多人採用了如下辦法,首先對取得字串按照 iso8859-1 進行解碼轉換,然後再按照 gb2312 進行編碼,最後得到正確的內容。範例程式碼如下:
頁面傳參:http://xxx.do?ptname='我是中國人'
後台轉換:

String strPtname = request.getParameter("ptname");strPtname = new String(strPtname.getBytes("ISO-8859-1"), "UTF-8");String para = new String( request.getParameter("para").getBytes("iso8859-1"), "gb2312"); 

具體的原因是因為美國人在寫 tomcat 時預設使用 iso8859-1 進行編碼造成的。 
然而,在我們的 servlet 和 jsp 頁面中有大量的參數需要進行傳遞,這樣轉換的話會帶來大量的轉碼,非常不便。

 
二、入門級解決方案 
後來,大家開始寫一個過濾器,在取得用戶端傳過來的參數之前,通過過濾器首先將取得的參數編碼設定為 gb2312 ,然後就可以直接使用 getParameter 取得正確的參數了。這個過濾器在 tomcat 的範例程式碼jsp-examples 中有詳細的使用樣本, 其中過濾器在 web.xml 中的設定如下,樣本中使用的是日文的編碼,我們只要修改為 gb2312 即可 
view plaincopy to clipboardprint?

<filter>    <filter-name>Set Character Encoding</filter-name>    <filter-class>filters.SetCharacterEncodingFilter</filter-class>    <init-param>    <param-name>encoding</param-name>    <param-value>EUC_JP</param-value>    </init-param>    </filter>   <filter> <filter-name>Set Character Encoding</filter-name> <filter-class>filters.SetCharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>EUC_JP</param-value> </init-param> </filter> 

 過濾器的代碼如下: 

public class SetCharacterEncodingFilter implements Filter {    // 編碼的字串    protected String encoding = null;    // 過濾器的配置    protected FilterConfig filterConfig = null;    // 是否忽略用戶端的編碼    protected boolean ignore = true;    // 銷毀過濾器    public void destroy() {    this.encoding = null;    this.filterConfig = null;    }    // 過濾方法    public void doFilter(ServletRequest request, ServletResponse response,    FilterChain chain)    throws IOException, ServletException {    // 如果使用過濾器,忽略用戶端的編碼,那麼使用通過過濾器設定編碼    if (ignore || (request.getCharacterEncoding() == null)) {    String encoding = selectEncoding(request);    if (encoding != null)    request.setCharacterEncoding(encoding);    }    // 傳送給下一個過濾器    chain.doFilter(request, response);    }      // 初始化過濾器    public void init(FilterConfig filterConfig) throws ServletException {    this.filterConfig = filterConfig;    this.encoding = filterConfig.getInitParameter("encoding");    String value = filterConfig.getInitParameter("ignore");    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;    }    // 返回過濾器設定的編碼    protected String selectEncoding(ServletRequest request) {    return (this.encoding);    }    }   public class SetCharacterEncodingFilter implements Filter { // 編碼的字串 protected String encoding = null; // 過濾器的配置 protected FilterConfig filterConfig = null; // 是否忽略用戶端的編碼 protected boolean ignore = true; // 銷毀過濾器 public void destroy() { this.encoding = null; this.filterConfig = null; } // 過濾方法 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 如果使用過濾器,忽略用戶端的編碼,那麼使用通過過濾器設定編碼 if (ignore || (request.getCharacterEncoding() == null)) { String encoding = selectEncoding(request); if (encoding != null) request.setCharacterEncoding(encoding); } // 傳送給下一個過濾器 chain.doFilter(request, response); }// 初始化過濾器 public void init(FilterConfig filterConfig) throws ServletException { this.filterConfig = filterConfig; this.encoding = filterConfig.getInitParameter("encoding"); String value = filterConfig.getInitParameter("ignore"); 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; } // 返回過濾器設定的編碼 protected String selectEncoding(ServletRequest request) { return (this.encoding); } } 

 然而在 tomcat5 中,即使使用過濾器,仍然可能取得亂碼,原因何在呢?
 
三、進階解決方案 
原來,在 tomcat4 和 tomcat5 中,對參數的處理是不一樣的!
在 tomcat4 中, get 與 post 的編碼是一樣的,所以只要在過濾器中通過 request.setCharacterEncoding 設定一次就可以解決 get 與 post 的問題。
然而,在 tomcat5 中,get 與 post 的處理卻是分開進行的 !
在 tomcat 5 中,為瞭解決編碼問題,tomcat 的作者作了很多努力,具體表現為在 tomcat 的設定檔 server.xml 中對 Connector 元素增加了如下的配置參數,專門用來對編碼進行直接的配置 
URIEncoding 用來設定通過 URI 傳遞的內容使用的編碼,tomcat 將使用這裡指定的編碼對用戶端傳送的內容進行編碼。 
什麼是 URI 呢? 
java doc 的說明中如下說明:URI 是統一資源識別項,而 URL 是統一資源定位器。因此,籠統地說,每個 URL 都是 URI,但不一定每個 URI 都是 URL。這是因為 URI 還包括一個子類,即統一資源名稱 (URN),它命名資源但不指定如何定位資源。
 
也就是說,我們通過 post 方法提交的參數實際上都是通過 uri 提交的,都由這個參數管理,如果沒有設定這個參數,則 tomcat 將使用預設的 iso8859-1 對用戶端的內容進行編碼!
 
useBodyEncodingForURI 使用與 Body 一樣的編碼來處理 URI, 這個設定是為了與 tomcat4保持相容。在 tomcat5 中,對post  的處理通過 前面的 URIEncoding 進行處理,對get 的內容依然通過 request.setCharacterEncoding 處理,為了保持相容,就有了這個設定。 
將 useBodyEncodingForURI 設定為真後,就可以通過 request.setCharacterEncoding 直接解決 get 和 post 中的亂碼問題。 
這樣,我們可以通過在 server.xml 中設定 URIEncoding 來解決 get 方法中的參數問題,使用過濾器來解決 post 方法中的問題。 
或者也可以通過在 server.xml 中設定 useBodyEncodingForURI 為 true ,配合過濾器來解決編碼的問題。 
在這裡,我強烈建議在網站的創作過程中,全程使用 utf-8 編碼來徹底解決亂碼問題。 
具體操作如下: 
1、頁面內容使用 utf-8 格式儲存,在頁面中加入 <mete http-equiv="contentType" content="textml;charst=utf-8"> 
2、伺服器端的 server.xml 中設定 useBodyEncodingForURI = true 
3、使用過濾器,過濾器設定編碼為 utf-8

四:如果有一些轉碼也轉不過來的話,可是試試開啟tomcat的server.xml,找到

<Connector acceptCount="100" connectionTimeout="20000" disableUploadTimeout="true" port="80" redirectPort="8443"> 

並在最後加上useBodyEncodingForURI="true" URIEncoding="UTF-8",如下

<Connector acceptCount="100" connectionTimeout="20000" disableUploadTimeout="true" port="80" redirectPort="8443"  useBodyEncodingForURI="true" URIEncoding="UTF-8">

 五:
如果用JSTL的話,可以自己寫一個el的function,調用URLEncoder.encode來編碼。

IE預設對URL後面的參數是不編碼發送的,但是tomat預設是按ISO8859-1來進行URL解碼,因此才會出現上述錯誤。好的做法是:

1、在URL參數中確保用UTF-8編碼之,方法可以用js函數encodeURI(),或調用自訂的el function;
2、設定server.xml中的Connector熟悉URIEncoding="UTF-8",確保解碼格式與編碼格式統一;

方法四:

<mce:script type="text/javascript"><!--   for(var i=0;i<document.links.length;i++){     document.links[i].href=encodeURI(document.links[i].href);     }   // --></mce:script>  <mce:script type="text/javascript"><!--for(var i=0;i<document.links.length;i++){document.links[i].href=encodeURI(document.links[i].href);}// --></mce:script>

 在action中:

String s=request.getParameter("s");s=new String(s.getBytes("iso-8859-1"),"gbk");

六:js的亂碼解決

1.用戶端:

url=encodeURI(url);

伺服器:

String linename = new String(request.getParameter("name").getBytes("ISO-8859-1"),"UTF-8");

2.用戶端:

url=encodeURI(encodeURI(url)); //用了2次encodeURI 

這個,是比較推崇的做法,為什麼這麼做,是有原因的,稍後整理下貼上來~~~

伺服器:

String linename = request.getParameter(name);

//java  : 字元解碼

linename = java.net.URLDecoder.decode(linename , "UTF-8");

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.