jQuery ajax在GBK編碼下表單提交終極解決方案(非二次編碼方法)
前言:
當jquery ajax在utf-8編碼下(頁面utf-8,接收utf-8),無任何問題。可以正常post、get,處理頁面直接獲取正確的內容。
但在以下情況下:
GBK -> AJAX POST ->GBK
UTF-8 -> AJAX POST ->GBK
後臺程式碼無法獲取正確的內容,通常表現為獲取到奇怪字元、問號。
經典解決方法:
1:傳送頁面、接收頁面均採用UTF-8編碼。
2:傳送頁面在呼叫ajax post方法之前,將含有中文內容的input用encodeURIComponent編碼一次,而接收頁面則呼叫解碼方法( 如:java.net.urldecoder.decode("接收到內容","utf-8") )。
其中,第一種方法無疑是最簡單、最直接,但往往不符合實際,因為很多專案並不是使用utf-8編碼,例如國內大部分使用gbk編碼,也不可能為了解決這樣一個問題,而將整個專案轉換為utf-8編碼,成本太大,風險太高。
第二方法,是現在最多人使用的方法,俗稱二次編碼,為什麼叫二次編碼,等下會解釋。客戶端編碼兩次,服務端解碼兩次。但這種方法不好的地方,就是前臺手動編碼一次,後臺再手動解碼一次,稍不留神就會忘記,而且程式碼摻和前臺邏輯。
互動過程:
當我們使用表單按照傳統方式post提交時候(非AJAX提交),瀏覽器會根據當前頁面編碼,encode一次,然後傳送到服務端,服務端接收到表單,會自動dencode一次,通常這個過程是對程式是透明的,因此加上手動編碼、解碼,就變成上面所說的二次編碼。
但當我們使用AJAX方式提交時候,瀏覽器並不會自動替我們encode,因此在jquery中有這樣的一段程式碼:
?1 2 3 4 5 6 7 8 9 10 11 12 13 |
ajax: function ( s ) {
// Extend the settings, but re-extend 's' so that it can be
// checked again later (in the test suite, specifically)
s = jQuery.extend( true , s, jQuery.extend( true ,
{}, jQuery.ajaxSettings, s)); var
jsonp, jsre = /=?(&|$)/g, status, data,
type = s.type.toUpperCase();
// convert data if not already a string
if
( s.data && s.processData && typeof
s.data !== "string"
)
s.data = jQuery.param(s.data);
........
}
|
以上是jquery的ajax方法的程式碼片段,下面是正常呼叫jquery ajax post的程式碼:
?1 2 3 4 5 6 7 8 9 10 |
$.ajax({
url: ajaxurl,
type:
'POST' ,
dataType:
'html' ,
timeout: 20000, //超時時間設定
data:para, //引數設定
success:
function (html){
}
});
|
通過上面程式碼可以知道,當設定了data時候,jquery內部會呼叫jQuery.param方法對引數encode(執行本應瀏覽器處理的encode)。
?1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
jQuery.param= function ( a ) {
var
s = [ ];
function
add( key, value ){
s[ s.length ] = encodeURIComponent(key) +
'=' + encodeURIComponent(value);
};
// If an array was passed in, assume that it is an array
// of form elements
if
( jQuery.isArray(a) || a.jquery )
// Serialize the form elements
jQuery.each( a,
function (){
add(
this .name,
this .value );
});
// Otherwise, assume that it's an object of key/value pairs
else
// Serialize the key/values
for
( var
j in a )
// If the value is an array then the key names need to be repeated
if
( jQuery.isArray(a[j]) )
jQuery.each( a[j],
function (){
add( j,
this );
});
else
add( j, jQuery.isFunction(a[j]) ? a[j]() : a[j] );
// Return the resulting serialization
return
s.join( "&" ).replace(/%20/g,
"+" );
} //jquery.param end
|
上面是jQuery.param的程式碼,細心點可以留意到encodeURIComponent這方法,這是javascript內建的方法,對目標字串執行utf-8 encode,因此,當頁面使用gbk編碼時候,服務端會使用gbk進行解碼,但實際提交的資料是以utf-8編碼的,所以造成接收到內容為亂碼或者為問號。
解決方法:
encodeURIComponent會以utf-8編碼,在gbk編碼下,可不可以以gbk進行編碼呢?
如果還在打encodeURIComponent主意的話,那不好意思,encodeURIComponent只會utf-8編碼,並沒有其他api進行其他編碼;不過,別擔心,看看下面:
encodeURIComponent,它是將中文、韓文等特殊字元轉換成utf-8格式的url編碼。
escape對0-255以外的unicode值進行編碼時輸出%u****格式,其它情況下escape,encodeURI,encodeURIComponent編碼結果相同。
哈哈,看到希望吧?沒錯,就是用escape代替encodeURIComponent方法,不過必須注意:
escape不編碼字元有69個:*,+,-,.,/,@,_,0-9,a-z,A-Z
encodeURIComponent不編碼字元有71個:!, ',(,),*,-,.,_,~,0-9,a-z,A-Z
使用了escape之後必須對加號進行編碼,否則,當內容含有加號時候會被服務端翻譯為空格。
終於知道解決辦法了,重寫jquery程式碼:
?1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
jQuery.param= function ( a ) {
var
s = [ ];
var
encode= function (str){
str=escape(str);
str=str.replace(/+/g, "%u002B" );
return
str;
};
function
add( key, value ){
s[ s.length ] = encode(key) +
'=' + encode(value);
};
// If an array was passed in, assume that it is an array
// of form elements
if
( jQuery.isArray(a) || a.jquery )
// Serialize the form elements
jQuery.each( a,
function (){
add(
this .name,
this .value );
});
// Otherwise, assume that it's an object of key/value pairs
else
// Serialize the key/values
for
( var
j in a )
// If the value is an array then the key names need to be repeated
if
( jQuery.isArray(a[j]) )
jQuery.each( a[j],
function (){
add( j,
this );
});
else
add( j, jQuery.isFunction(a[j]) ? a[j]() : a[j] );
// Return the resulting serialization
return
s.join( "&" ).replace(/%20/g,
"+" );
}
|
上面那段程式碼並不需要在jquery的原始檔重寫,可以在你專案的javascript貼上,覆蓋它原有的方法,不過必須在jquery載入之後。
經初步驗證,上面那段程式碼在utf-8編碼也可以工作正常,大概是編碼成unicode的緣故吧。
這樣,就不是需要使用什麼二次編碼,即影響前臺,又影響後臺。gbk編碼下ajax post不再是問題了,此乃是終極解決方法。哈哈。
編輯 置頂 移動 刪除 回覆 <!--收藏--> sushi0k #2樓 發表於:2011-01-28 18:02:06 編輯 刪除 回覆 引用作者你好,看到你的文章講解的很詳細,讓初學者和第一次遇到這種問題的人都能夠大致瞭解問題所在。
我的問題是,我在jsp頁面貼上了你的jQuery.param函式。然後我在servlet獲取引數的時候出現了報錯:
System.out.println(request.getParameter("vals"));//執行這句的時候,出現瞭如下錯誤。
java.io.CharConversionException: isHexDigit
按樓主的文章所述,似乎沒有提到servlet需要進行一些處理。還是樓主遺漏了。
還請樓主提示一些,偶還沒懂。我的email是[email protected]
QQ:759063617 感謝樓主的文章。
編輯 刪除 回覆 引用 路路 #3樓 發表於:2011-01-28 18:51:18 編輯 刪除 回覆 引用不需要什麼後續處理的噢....
平時怎麼接收.....還是那樣接收...
按照你的說法...你還沒解決接收中文問題......tomcat的嗎?
編輯 刪除 回覆 引用 wanglei_licnancan #4樓 發表於:2011-04-06 15:16:39 編輯 刪除 回覆 引用樓主您好!
我已經將jQuery.param函式貼在jsp頁面中,但是後臺取到的中文仍是亂碼,是weblogic環境,由於專案編碼所限,頁面以及sevlet均是GBK編碼,請問,除了將param方法貼在JSP頁面中,還需要做什麼嘛?
我的QQ:88358148,望樓主指教~ 感激不盡!
謝謝!
編輯 刪除 回覆 引用 lulu #5樓 發表於:2011-04-06 20:05:30 編輯 刪除 回覆 引用你可以用firebug看看加log或者alert看看,看是否有執行上面的程式碼。
一般,如果起作用,接受引數的jsp或者setvlet都沒問題的。
編輯 刪除 回覆 引用 showicy #6樓 發表於:2011-05-14 13:08:10 編輯 刪除 回覆 引用不太理解:
用escape對中文進行的是unicode編碼。
而服務端用gbk進行解碼。
編碼跟解碼字符集不對,這樣不會亂碼嗎???
編輯 刪除 回覆 引用 lulu #7樓 發表於:2011-05-15 18:05:17 編輯 刪除 回覆 引用unicode跟字符集沒關係吧,所有東西都可以以unicode表示
編輯 刪除 回覆 引用 rain85922 #8樓 發表於:2011-08-22 10:44:22 編輯 刪除 回覆 引用樓主你好,用你這個重寫jquery的程式碼 這一行在IE8下報錯了
str=str.replace(/+/g,"%u002B");
說+ 是“錯誤的數量詞”
別的字元好像就可以 如-
另:我將str=str.replace(/+/g,"%u002B");改為str=str.replace(/+/g,"%u002B");
在頁面上加上該段程式碼後,頁面提交form,整個bean中包含中文的屬性在後臺都變為null了
編輯 刪除 回覆 引用 lulu #9樓 發表於:2011-08-22 16:08:26 編輯 刪除 回覆 引用改成這樣試試:
str=str.replace(/\+/g,"%u002B");
編輯 刪除 回覆 引用 lcffufly #10樓 發表於:2011-09-09 16:03:10 編輯 刪除 回覆 引用測試失敗,請樓主指導一下:萬分感謝!
?1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
<html>
<meta http-equiv= "Content-Type"
content= "text/html; charset=gbk"
/>
<body>
11111111111
</body>
<script type= "text/javascript"
src= "jquery-1.4.2.min.js" ></script>
<script type= "text/javascript" >
jQuery.param= function ( a ) {
var
s = [ ];
var
encode= function (str){
str = encodeURIComponent(str);
//str=escape(str);
//str=str.replace(/+/g,"%u002B");
return
str;
};
function
add( key, value ){
s[ s.length ] = encode(key) +
'=' + encode(value);
};
// If an array was passed in, assume that it is an array
// of form elements
if
( jQuery.isArray(a) || a.jquery )
// Serialize the form elements
jQuery.each( a,
function (){
add(
this .name,
this .value );
});
// Otherwise, assume that it's an object of key/value pairs
else
// Serialize the key/values
for
( var
j in a )
// If the value is an array then the key names need to be repeated
if
( jQuery.isArray(a[j]) )
jQuery.each( a[j],
function (){
add( j,
this );
});
else
add( j, jQuery.isFunction(a[j]) ? a[j]() : a[j] );
$b =s.join( "&" ).replace(/%20/g,
"+" );
console.log($b);
// Return the resulting serialization
return
$b;
}
$.ajax({
url: 'test.php',
data:{
name: "臨風"
},
timeout: 20000, //超時時間設定 data:para,//引數設定
success:
function (html){
}
});
</script>
</html>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<?php
var_dump($_REQUEST);
echo $_REQUEST[ 'name' ], "
" ;
echo utf2gbk($_REQUEST[ 'name' ]);
function
utf2gbk($data){
if (is_array($data)){
return
array_map( "utf2gbk" ,$data);
}
return
iconv( "utf-8" , 'gbk' ,$data);
}
function
gbk2utf8($data){
if (is_array($data)){
return
array_map( "utf2gbk" ,$data);
}
return
iconv( "gbk" , 'utf-8' ,$data);
}
?>
|
array(1) {
["name"]=>
string(12) "%u4E34%u98CE"
}
%u4E34%u98CE
%u4E34%u98CE