1. 程式人生 > >解決ajax提交表單出現亂碼的問題

解決ajax提交表單出現亂碼的問題

問題

在現有主站中使用的是是GBK編碼的,當表單使用formsubmit方式遞交的話沒有問題,伺服器端能夠正確識別字符編碼。但是,當客戶端使用ajax的方式遞交表單的話,伺服器端識別客戶端遞交的表單的內容,當內容中有中文字元的話就會出現亂碼現象。

原因分析

究其原因,其實很簡單,使用ajax方式提交的表單是用utf-8編碼來提交的,這樣伺服器端在接收客戶端表單的內容的時候還是按照GBK或其他編碼方式來解析的,自然解析出來的內容會出現亂碼了。

表單內容可以通過GET或POST方式傳送,但是用這兩種方式有幾個不同之處,對“你好”呼叫javascript函式encodeURI()解析之後得到的字串為“%E4%BD%A0%E5%A5%BD”,需要注意的一點,encodeURI()這個函式只會對字串進行utf8編碼。當客戶端把“%E4%BD%A0%E5%A5%BD”這段字串通過GET或者POST方式傳送會發生什麼事。

1.GET方式

當用get方式提交表單,在服務端的tomcat伺服器中會用一個connector來自動解析編碼之後字串,以下是connector的配置節點:

<Connector port="80"
 maxHttpHeaderSize="8192"
 maxThreads="150" minSpareThreads="25"
 maxSpareThreads="75"
 enableLookups="false" redirectPort="8443"
 acceptCount="100"
 connectionTimeout="20000" disableUploadTimeout="true"
 URIEncoding="GBK" />

上面配置中有一個屬性URIEncoding="GBK"的作用是,當客戶端get傳送資訊中有encode模式的字串就是用gbk來decode它。和遺憾,主站伺服器中的URIEncoding屬性是gbk不能變了,而客戶端encodeURI()只能編碼UTF-8的字元。所以,用這種方式傳送的字串在伺服器端就會出現亂碼現象。

2. POST方式

當客戶端傳送“%E4%BD%A0%E5%A5%BD”字串時,是通過YAHOO.util.Connect這個控制元件來發送的,如果客戶端能正常地傳送“%E4%BD%A0%E5%A5%BD”這個字串,服務端接收到之後並不會做額外的轉義,但是YAHOO.util.Connect將encode之後字串傳給Connect控制元件之後,這個控制元件在內部會將encode之後的字元再decode之後再發送,因為傳送的是utf-8格式的內容,所以伺服器端就會出現亂碼。

解決辦法

嘗試了以上get和post方式之後,覺得在請求的URL上傳送資料亂碼問題的解決方案比較麻煩,況且,http協議中已經明確說了get和post的區別,get是從伺服器端拿一些東西,而post是向伺服器傳輸東西。get方式向伺服器端傳送資料的資料量有限,且get傳輸也是不

安全的。

那麼我們只能來解決YAHOO.util.Connect這個控制元件傳送請求之前自動轉義字元的問題。以下是Connect傳送非同步請求的一段程式碼

var postData="city="+from["city"].value
+"&areainfo="+from["areainfo"].value +"&store.name="+encodeURI(encodeURI(from["store.name"].value))
YAHOO.util.Connect.asyncRequest('POST',formObject.action, callback,postData);

如上所示,可以呼叫兩遍encodeURI,

例如:“你好”

·呼叫一遍encodeURI:“%E4%BD%A0%E5%A5%BD”

·呼叫兩遍encodeURI: “%25E4%25BD%25A0%25E5%25A5%25BD”

當把第二遍encode的結果傳給YAHOO.util.Connect控制元件,控制元件會decode成第一遍呼叫encodeURI的輸出結果,這樣就能把“你好”的utf-8編碼傳輸到伺服器上去了。

在伺服器的webwork的action或者interceptor中先對傳輸上來的內容做一次decode,注意一定要用utf-8解碼。示例

try {
HttpServletRequest request
 = ServletActionContext.getRequest();
String storeName = request.getParameter("store.name");
this.getStore().setName(
  URLDecoder.decode(StringUtils.trimToEmpty(storeName)
    ,"UTF-8"));
this.getStore().setAddress(
 URLDecoder.decode(
  StringUtils.trimToEmpty(request
   .getParameter("store.address")), "UTF-8"));
} catch (Exception e) {
   throw new RuntimeException(e);
}
總結

通過以上提到的在客戶端中將用ajax遞交的欄位內容兩次呼叫encodeURI的方法,能夠很好地解決伺服器端使用非utf8的而造成的亂碼問題。

出現這樣的問題,主要原因是客戶端javascript的編碼只支援utf編碼,而伺服器端能夠按照架構師的需要定義各種編碼,口碑現在伺服器端使用的是GBK的編碼格式,但是隨著業務擴充套件,某些應用模組使用了utf的編碼格式,這樣在伺服器端由於編碼不統一,在做兩個不同編碼的格式系統的產品的時候給程式設計師帶來了無盡的煩惱。例如,sa同時經常會問這樣的問題,呼叫資料庫的應用有用gbk編碼的,也有用utf8編碼的,那麼資料庫應該用啥編碼的呢?

最近口碑的工程師們為現在一直為到底是用gbk編碼還是用UTF8編碼在進行討論,我們現在討論的焦點似乎是哪個編碼更加好。但是我覺得,就編碼來說擴充套件性當然是utf8,如果以後口碑要打入國際市場,到時候要出一個阿拉伯語版本的應用時候就可以輕鬆搞定了。我倒是覺得討論那個編碼好沒有什麼實際意義,關鍵是如何解決現在編碼混亂的局面,如何讓編碼統一,這個才是我們應該關注的焦點。這樣在將來的專案中我們的工程師不再會因為編碼問題而頭痛了。

所以我的個人觀點是,當你開始搭建一個新的系統的時候,一開始就把utf-8作為你的專案中使用的編碼格式,並且要把這個成為你專案的規約,寫進你們專案組的“憲法”中去。這樣,在以後會為你免去很多不必要的麻煩。