<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    tory320

      BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      10 隨筆 :: 0 文章 :: 1 評(píng)論 :: 0 Trackbacks
    ?
    在用 AJAX 開(kāi)發(fā)的過(guò)程中, 不可避免的會(huì)遇到中文問(wèn)題. 很多原來(lái)可以通過(guò)表單進(jìn)行 POST 提交的字符, 到了用 AJAX 實(shí)現(xiàn)的時(shí)候, 就會(huì)出現(xiàn)煩人的亂碼和丟特殊字符的現(xiàn)象. 另外服務(wù)器端返回值如何解析, 也是一個(gè)很煩人的問(wèn)題. 本文將就個(gè)人的一點(diǎn)實(shí)踐經(jīng)驗(yàn)作出總結(jié), 并給出一個(gè)盡量簡(jiǎn)單可行, 復(fù)用性高的方案. 目的不是替代你喜歡的 AJAX 框架, 而是希望幫助您理解和處理可能遇到的問(wèn)題.

    開(kāi)始之前: 首先一個(gè)問(wèn)題就是通常 XMLHttpRequest 默認(rèn)的編碼都是UTF-8的, 所以我們建議所有頁(yè)面, 客戶端和服務(wù)器端都使用 UTF-8 作為編碼.

    1. base64 encode 和 decode
    ??? 這個(gè)方案依賴于 JavaScript 實(shí)現(xiàn)的 base64 編碼/解碼方法, 在客戶端發(fā)送參數(shù)的時(shí)候用 base64 進(jìn)行編碼, 服務(wù)器端通過(guò) base64 進(jìn)行解碼后還原出原來(lái)的字符, 這個(gè)解決方案可以滿足需要, 但是有個(gè)問(wèn)題就是一是增加了客戶端代碼量, 還有個(gè)大問(wèn)題就是編碼后的內(nèi)容比原始內(nèi)容會(huì)大很多, 另外如果找到的 base64 JS 算法不夠標(biāo)準(zhǔn)的話, 服務(wù)器端就無(wú)法還原原來(lái)的值了. 現(xiàn)在網(wǎng)上有很多種 base64 的 JS 實(shí)現(xiàn)代碼, 例如如下的一個(gè)算法實(shí)現(xiàn):

    <HTML>
    <HEAD>
    <TITLE>Base64</TITLE>
    <script language=javascript>
    var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    var base64DecodeChars = new Array(
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
      -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
      52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
      -1,  0, 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, -1, -1, -1, -1, -1,
      -1, 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, -1, -1, -1, -1, -1);
    function base64encode(str) {
      var out, i, len;
      var c1, c2, c3;
      len = str.length;
      i = 0;
      out = "";
      while (i < len) {
    ?c1 = str.charCodeAt(i++) & 0xff;
    ?if(i == len)
    ?{
       out += base64EncodeChars.charAt(c1 >> 2);
       out += base64EncodeChars.charAt((c1 & 0x3) << 4);
       out += "==";
       break;
    ?}
    ?c2 = str.charCodeAt(i++);
    ?if(i == len)
    ?{
       out += base64EncodeChars.charAt(c1 >> 2);
       out += base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));
       out += base64EncodeChars.charAt((c2 & 0xF) << 2);
       out += "=";
       break;
    ?}
    ?c3 = str.charCodeAt(i++);
    ?out += base64EncodeChars.charAt(c1 >> 2);
    ?out += base64EncodeChars.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));
    ?out += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6));
    ?out += base64EncodeChars.charAt(c3 & 0x3F);
      }
       return out;
    }
    function base64decode(str) {
      var c1, c2, c3, c4;
      var i, len, out;
      len = str.length;
      i = 0;
      out = "";
      while (i < len) {
    ?/* c1 */
    ?do {
       c1 = base64DecodeChars[str.charCodeAt(i++) & 0xff];
    ?} while(i < len && c1 == -1);
    ?if(c1 == -1)
       break;
    ?/* c2 */
    ?do {
       c2 = base64DecodeChars[str.charCodeAt(i++) & 0xff];
    ?} while(i < len && c2 == -1);
    ?if(c2 == -1)
       break;
    ?out += String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4));
    ?/* c3 */
    ?do {
       c3 = str.charCodeAt(i++) & 0xff;
       if(c3 == 61)
     return out;
       c3 = base64DecodeChars[c3];
    ?} while(i < len && c3 == -1);
    ?if(c3 == -1)
       break;
    ?out += String.fromCharCode(((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2));
    ?/* c4 */
    ?do {
       c4 = str.charCodeAt(i++) & 0xff;
       if(c4 == 61)
     return out;
       c4 = base64DecodeChars[c4];
    ?} while(i < len && c4 == -1);
    ?if(c4 == -1)
       break;
    ?out += String.fromCharCode(((c3 & 0x03) << 6) | c4);
      }
       return out;
    }
    function utf16to8(str) {
      var out, i, len, c;
      out = "";
      len = str.length;
      for(i = 0; i < len; i++) {
    ?c = str.charCodeAt(i);
    ?if ((c >= 0x0001) && (c <= 0x007F)) {
       out += str.charAt(i);
    ?} else if (c > 0x07FF) {
       out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F));
       out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F));
       out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
    ?} else {
       out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F));
       out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
    ?}
      }
       return out;
    }
    function utf8to16(str) {
      var out, i, len, c;
      var char2, char3;
      out = "";
      len = str.length;
      i = 0;
      while (i < len) {
    ?c = str.charCodeAt(i++);
    ?switch(c >> 4)
    ?{
      case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
       // 0xxxxxxx
       out += str.charAt(i-1);
       break;
      case 12: case 13:
       // 110x xxxx  10xx xxxx
       char2 = str.charCodeAt(i++);
       out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));
       break;
      case 14:
       // 1110 xxxx 10xx xxxx 10xx xxxx
       char2 = str.charCodeAt(i++);
       char3 = str.charCodeAt(i++);
       out += String.fromCharCode(((c & 0x0F) << 12) |
         ((char2 & 0x3F) << 6) |
         ((char3 & 0x3F) << 0));
       break;
    ?}
      }
       return out;
    }

    function doit() {
      var f = document.f
       f.output.value = base64encode(utf16to8(f.source.value))
       f.decode.value = utf8to16(base64decode(f.output.value))
    }
    </script>
    </HEAD>
    <BODY>
    <H1>Base64</H1>
    <FORM NAME="f">
    原碼& lt;BR>
    <TEXTAREA NAME="source" ROWS=4 COLS=60 WRAP="soft"></TEXTAREA><BR><BR>
    Base64 encode<BR>
    <TEXTAREA NAME="output" ROWS=4 COLS=60 WRAP="soft"></TEXTAREA><BR><BR>
    Base64 decode<BR>
    <TEXTAREA NAME="decode" ROWS=4 COLS=60 WRAP="soft"></TEXTAREA><BR><BR>
    <INPUT TYPE=BUTTON VALUE="轉(zhuǎn)換" ONCLICK="doit()">
    </FORM>
    </BODY>

    在每個(gè)表單值被提交之前調(diào)用 base64encode, 然后在服務(wù)器端調(diào)用 base64 解碼器即可.
    在 JSP 中可以通過(guò)這樣做來(lái)實(shí)現(xiàn):
    ??? ??? sun.misc.BASE64Decoder base64decoder = new sun.misc.BASE64Decoder();
    ??? ??? byte[] data =?base64decoder.decodeBuffer(request.getParameter("input"));
    ??? ??? String result = new String(data, "UTF-8");// 注意建議這里制定字符集來(lái)歡迎到原來(lái)的字符串

    在這種情況下服務(wù)器端返回的字符也可以通過(guò)先 base64 編碼的方式傳遞到客戶端, 客戶端之后調(diào)用 JS 形式的解碼器即可還原到原來(lái)的字符串. 服務(wù)器端可以使用 sun.misc.BASE64Encoder (不要用 java.netURLEncoder).

    2.使用 JS 自帶的 escape() & encodeURI() & encodeURIComponent()

    escape() & encodeURI() & encodeURIComponent()這三個(gè)函數(shù)都可以用來(lái)對(duì)URI進(jìn)行encode或過(guò)濾特殊字符(#/$&+=?/等)。我的經(jīng)驗(yàn)是最好用encodeURIComponent()(需要IE 5.5以上,F(xiàn)ireFox當(dāng)然沒(méi)問(wèn)題),因?yàn)閷?duì)UTF-8支持比較好,不會(huì)遇到中文亂碼問(wèn)題,否則還需要進(jìn)行編碼轉(zhuǎn)換,很麻煩的。使用其它兩個(gè)函數(shù)都會(huì)發(fā)生丟失特殊字符的問(wèn)題,例如空格變+號(hào)或者空格,引號(hào),&=?等丟失的問(wèn)題, 至少使用 JSP 作為服務(wù)器端的話會(huì)發(fā)生這種情況, 有興趣的朋友可以將本文最后的例子代碼中的編碼部分修改后做個(gè)測(cè)試.

    下面是MSDN上對(duì)這三個(gè)函數(shù)的解釋:

    escape(charString)

    The escape method returns a string value (in Unicode format) that contains the contents of charstring. All spaces, punctuation, accented characters, and any other non-ASCII characters are replaced with %xx encoding, where xx is equivalent to the hexadecimal number representing the character. For example, a space is returned as "%20."

    Characters with a value greater than 255 are stored using the %uxxxx format.

    Note?? The escape method should not be used to encode Uniform Resource Identifiers (URI). Use encodeURI and encodeURIComponent methods instead.

    http://msdn.microsoft.com/library/en-us/script56/html/js56jsmthescape.asp

    ?encodeURI(URIString)

    The encodeURI method returns an encoded URI. If you pass the result to decodeURI, the original string is returned. The encodeURI method does not encode the following characters: ":", "/", ";", and "?". Use encodeURIComponent to encode these characters.

    http://msdn.microsoft.com/library/en-us/script56/html/js56jsmthfencodeuri.asp

    encodeURIComponent(encodedURIString)

    The encodeURIComponent method returns an encoded URI. If you pass the result to decodeURIComponent, the original string is returned. Because the encodeURIComponent method encodes all characters, be careful if the string represents a path such as /folder1/folder2/default.html. The slash characters will be encoded and will not be valid if sent as a request to a web server. Use the encodeURI method if the string contains more than a single URI component.

    http://msdn.microsoft.com/library/en-us/script56/html/js56jsmthencodeuricomponent.asp

    3. 使用一個(gè)簡(jiǎn)便的客戶端數(shù)據(jù)解析方案

    最偷懶的辦法就是返回一段 HTML 顯示出來(lái)了. 至于如果是想帶一些數(shù)據(jù), 解析處理的話, 方案很多, 利用 XML 啊, JSON 啊什么的不一而足. 我這里呢就給出一個(gè)相當(dāng)簡(jiǎn)便的方案: 使用 JS 內(nèi)置的 eval 方法來(lái)解析. 這個(gè)方案是在幫助一個(gè)同事想最快的已最短的代碼解析返回的對(duì)象的多個(gè)變量的時(shí)候提出的.

    服務(wù)器端返回一個(gè)字符串:
    var _dataObject = {
    ?? username : "beansoft",
    ??????? age : 24
    };

    客戶端在得到這個(gè)字符串后可以通過(guò)下面一段代碼搞定:
    var responseText = xmlhttp.responseText;
    eval(responseText);
    alert("_dataObject.username=" + _dataObject.username);

    好了, 解析出來(lái)了!
    如果要傳遞多個(gè)變量呢, 就用 var _dataObject1, var _dataObject2...這樣就可以了, 客戶端就依次是 _dataObject1.username, _dataObject2.username...

    等等: 我的變量里寫(xiě)了特殊字符怎么辦? 例如我用的字符串是 'abc"'', 這時(shí)候我不得不拋出殺手锏了, 這就是用 Java 實(shí)現(xiàn)的 escape(), unescape() 方法, 其實(shí)本例中只需要 escape() 的 Java 版本就可以了(這個(gè)方案也幫助另一個(gè)同事解決了從JSP端傳遞的變量含有'號(hào)結(jié)果導(dǎo)致客戶端沒(méi)法顯示的問(wèn)題):

    ??? public static String escape(String src) {
    ??? ??? int i;
    ??? ??? char j;
    ??? ??? StringBuffer tmp = new StringBuffer();
    ??? ??? tmp.ensureCapacity(src.length() * 6);
    ??? ??? for (i = 0; i < src.length(); i++) {
    ??? ??? ??? j = src.charAt(i);
    ??? ??? ??? if (Character.isDigit(j) || Character.isLowerCase(j)
    ??? ??? ??? ??? ??? || Character.isUpperCase(j))
    ??? ??? ??? ??? tmp.append(j);
    ??? ??? ??? else if (j < 256) {
    ??? ??? ??? ??? tmp.append("%");
    ??? ??? ??? ??? if (j < 16)
    ??? ??? ??? ??? ??? tmp.append("0");
    ??? ??? ??? ??? tmp.append(Integer.toString(j, 16));
    ??? ??? ??? } else {
    ??? ??? ??? ??? tmp.append("%u");
    ??? ??? ??? ??? tmp.append(Integer.toString(j, 16));
    ??? ??? ??? }
    ??? ??? }
    ??? ??? return tmp.toString();
    ??? }

    ??? public static String unescape(String src) {
    ??? ??? StringBuffer tmp = new StringBuffer();
    ??? ??? tmp.ensureCapacity(src.length());
    ??? ??? int lastPos = 0, pos = 0;
    ??? ??? char ch;
    ??? ??? while (lastPos < src.length()) {
    ??? ??? ??? pos = src.indexOf("%", lastPos);
    ??? ??? ??? if (pos == lastPos) {
    ??? ??? ??? ??? if (src.charAt(pos + 1) == 'u') {
    ??? ??? ??? ??? ??? ch = (char) Integer.parseInt(src
    ??? ??? ??? ??? ??? ??? ??? .substring(pos + 2, pos + 6), 16);
    ??? ??? ??? ??? ??? tmp.append(ch);
    ??? ??? ??? ??? ??? lastPos = pos + 6;
    ??? ??? ??? ??? } else {
    ??? ??? ??? ??? ??? ch = (char) Integer.parseInt(src
    ??? ??? ??? ??? ??? ??? ??? .substring(pos + 1, pos + 3), 16);
    ??? ??? ??? ??? ??? tmp.append(ch);
    ??? ??? ??? ??? ??? lastPos = pos + 3;
    ??? ??? ??? ??? }
    ??? ??? ??? } else {
    ??? ??? ??? ??? if (pos == -1) {
    ??? ??? ??? ??? ??? tmp.append(src.substring(lastPos));
    ??? ??? ??? ??? ??? lastPos = src.length();
    ??? ??? ??? ??? } else {
    ??? ??? ??? ??? ??? tmp.append(src.substring(lastPos, pos));
    ??? ??? ??? ??? ??? lastPos = pos;
    ??? ??? ??? ??? }
    ??? ??? ??? }
    ??? ??? }
    ??? ??? return tmp.toString();
    ??? }

    這樣, 在服務(wù)器端的時(shí)候可以變成:
    <%
    String username = "'abc\"''";// 其實(shí)這個(gè)普通子串轉(zhuǎn)換成 Java 語(yǔ)言中的字符串也有工具可以用的, 例如本人開(kāi)發(fā)的 Native2JavaString, 改日再講.
    %>
    var _dataObject = {
    ?? username : "<%=escape(username)%>",
    ??????? age : 24
    };
    客戶端呢, 就可以簡(jiǎn)單的來(lái)JS自帶的 unescape() 函數(shù)來(lái)取出原來(lái)的字符串:
    var responseText = xmlhttp.responseText;
    eval(responseText);
    alert("_dataObject.username=" + unescape(_dataObject.username));
    就是服務(wù)器端用 Java 寫(xiě)的 escape(), 客戶端呢就用 JS 自帶的 unescape().

    4.?實(shí)例代碼
    好了, 說(shuō)了這么多, 就推出個(gè)人的解決方案吧. 簡(jiǎn)單的講就是我寫(xiě)了一個(gè)腳本對(duì)象 AjaxFormer, 使用的是 escape來(lái)自動(dòng)的將原來(lái)的 POST/GET 方式的提交代碼自動(dòng)的轉(zhuǎn)換成 AJAX 的方式.

    /**
    ?* @constructor
    ?* This is a ajax form helper class.
    ?*
    ?* @param form - the document form
    ?* @param resultDivId - the result div id
    ?*/
    function AjaxFormer (form, resultDivId);

    構(gòu)造器的第一個(gè)參數(shù)是個(gè) form 對(duì)象, 第二個(gè)是個(gè)可選的結(jié)果 DIV 對(duì)象, 也就是說(shuō)你可以指定服務(wù)器端返回的 HTML 代碼顯示的地方, 如果保持為空的話, 那么返回的 HTML?會(huì)被附加到文檔的末尾. 本對(duì)象有一個(gè)名字為 ajaxSubmitForm() 的方法來(lái)自動(dòng)的遍歷所有表單元素, 然后將結(jié)果拼成一個(gè)字符串, 最后根據(jù)原來(lái)的表單的提交方式(get/post)來(lái)自動(dòng)再客戶端用 AJAX 模擬提交這個(gè)表單到原來(lái)的表單的 action 屬性所指定的頁(yè)面中去.

    用法示例:
    <html>

    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>AJAX Form Submit Test</title>
    <script src='ajax_common.js'></script>

    </head>

    <body>
    <h3>AJAX Form Submit Test</h3>
    Fill the form and then click submit
    <form method="POST" id="form1" name="form1"
    action="form_action.jsp"
    onSubmit="former.ajaxSubmitForm();return false;">
    ??? <p><input type="hidden" name="hidden1" value="hiddenValue">
    ??? text:<input type="text" name="textf&1" size="20" value="text1">
    ??? checkbox:<input type="checkbox" name="checkbox1" value="ON" checked>
    ??? radio:<input type="radio" value="V1" checked name="radio1">
    ??? select:<select size="1" name="select1">
    ??? <option selected value="option1">D1</option>
    ??? </select>
    ??? <br>
    ??? <br>
    ??? <input type="submit" name="B1" value="submit">
    ??? <input type="reset" name="B2" value="reset">
    ??? </p>
    </form>

    <script type="text/javascript">
    var former = new AjaxFormer($('form1'));
    </script>
    </body>

    </html>

    紅色的字體就是您從一個(gè)非 AJAX 的表單提交改變成一個(gè) AJAX 的表單提交所需要做的工作, 看上去夠簡(jiǎn)單吧?

    運(yùn)行時(shí)的效果如圖所示:
    http://m.tkk7.com/images/blogjava_net/beansoft/18680/o_ajaxFormer.png

    下載本文的源碼:?

    AJAXFormer.zip4KB

    將源碼解壓縮到JSP服務(wù)器的任意目錄下即可, 例如 $TOMCAT_HOME\webapps\ROOT 下, 然后在瀏覽器里鍵入:
    http://localhost:8080/ajax_form_submit.htm

    作者: beansoft@126.com?2006.12.25

    posted on 2006-12-25 21:01 tory 閱讀(770) 評(píng)論(1)  編輯  收藏

    評(píng)論

    # re: (轉(zhuǎn))JSP 中 AJAX 的表單提交中文問(wèn)題的簡(jiǎn)單解決方案 2007-05-17 16:58 中卜大
    林  回復(fù)  更多評(píng)論
      


    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: **aaaaa毛片免费| 亚洲av不卡一区二区三区| 无码人妻丰满熟妇区免费| 国产亚洲精品AAAA片APP| 久久精品国产亚洲av日韩| 亚洲麻豆精品国偷自产在线91| 亚洲免费综合色在线视频| 久久九九免费高清视频| 国产亚洲欧美在线观看| 亚洲AV成人一区二区三区在线看| 亚洲av无码不卡一区二区三区| 亚洲无码高清在线观看| 免费无码一区二区三区蜜桃大| 久草在视频免费福利| 69影院毛片免费观看视频在线 | 啦啦啦高清视频在线观看免费| 国产无遮挡裸体免费视频在线观看 | 亚洲激情校园春色| 亚洲AV综合色区无码另类小说| 亚洲欧洲日产国码高潮αv| 女人被男人躁的女爽免费视频| 久视频精品免费观看99| 一区二区三区在线免费看| 三上悠亚电影全集免费| 久久久久久久久久久免费精品| 老司机精品视频免费| 国产亚洲福利精品一区二区| 亚洲国产无线乱码在线观看 | 成人影片一区免费观看| 巨胸喷奶水视频www免费视频| 午夜免费国产体验区免费的| 美女被免费视频网站a| 免费国产黄网站在线看| 国产成人亚洲综合无| 精品亚洲视频在线| 国产成人亚洲午夜电影| 黄色a三级三级三级免费看| 美女被艹免费视频| 久久免费视频一区| 两性色午夜视频免费网| 久久精品电影免费动漫|