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

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

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

    tory320

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

    開始之前: 首先一個問題就是通常 XMLHttpRequest 默認的編碼都是UTF-8的, 所以我們建議所有頁面, 客戶端和服務器端都使用 UTF-8 作為編碼.

    1. base64 encode 和 decode
    ??? 這個方案依賴于 JavaScript 實現的 base64 編碼/解碼方法, 在客戶端發送參數的時候用 base64 進行編碼, 服務器端通過 base64 進行解碼后還原出原來的字符, 這個解決方案可以滿足需要, 但是有個問題就是一是增加了客戶端代碼量, 還有個大問題就是編碼后的內容比原始內容會大很多, 另外如果找到的 base64 JS 算法不夠標準的話, 服務器端就無法還原原來的值了. 現在網上有很多種 base64 的 JS 實現代碼, 例如如下的一個算法實現:

    <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="轉換" ONCLICK="doit()">
    </FORM>
    </BODY>

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

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

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

    escape() & encodeURI() & encodeURIComponent()這三個函數都可以用來對URI進行encode或過濾特殊字符(#/$&+=?/等)。我的經驗是最好用encodeURIComponent()(需要IE 5.5以上,FireFox當然沒問題),因為對UTF-8支持比較好,不會遇到中文亂碼問題,否則還需要進行編碼轉換,很麻煩的。使用其它兩個函數都會發生丟失特殊字符的問題,例如空格變+號或者空格,引號,&=?等丟失的問題, 至少使用 JSP 作為服務器端的話會發生這種情況, 有興趣的朋友可以將本文最后的例子代碼中的編碼部分修改后做個測試.

    下面是MSDN上對這三個函數的解釋:

    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. 使用一個簡便的客戶端數據解析方案

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

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

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

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

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

    ??? 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();
    ??? }

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

    4.?實例代碼
    好了, 說了這么多, 就推出個人的解決方案吧. 簡單的講就是我寫了一個腳本對象 AjaxFormer, 使用的是 escape來自動的將原來的 POST/GET 方式的提交代碼自動的轉換成 AJAX 的方式.

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

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

    用法示例:
    <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>

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

    運行時的效果如圖所示:
    http://m.tkk7.com/images/blogjava_net/beansoft/18680/o_ajaxFormer.png

    下載本文的源碼:?

    AJAXFormer.zip4KB

    將源碼解壓縮到JSP服務器的任意目錄下即可, 例如 $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 閱讀(765) 評論(1)  編輯  收藏

    評論

    # re: (轉)JSP 中 AJAX 的表單提交中文問題的簡單解決方案 2007-05-17 16:58 中卜大
    林  回復  更多評論
      


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 亚洲精品国产V片在线观看| 爱爱帝国亚洲一区二区三区| 亚洲高清成人一区二区三区| 日本在线高清免费爱做网站| 在线看片免费人成视频久网下载 | 亚洲色偷偷色噜噜狠狠99| 亚洲精品亚洲人成人网| 四只虎免费永久观看| 四虎1515hh永久久免费| 日本免费A级毛一片| 美女羞羞视频免费网站| 亚洲色大成网站www久久九| 亚洲明星合成图综合区在线| 亚洲成AV人片在| 亚洲成a人片在线观看老师| 在线观看免费国产视频| 处破痛哭A√18成年片免费| 1000部夫妻午夜免费| 日韩精品无码专区免费播放| 成人免费av一区二区三区| 一级毛片无遮挡免费全部| 日韩毛片在线免费观看| 色综合久久精品亚洲国产| 亚洲色无码国产精品网站可下载| 亚洲一区二区影视| 亚洲伊人精品综合在合线| 亚洲精品中文字幕乱码影院| 亚洲成色999久久网站| 亚洲AV无码乱码在线观看富二代 | 黄色毛片免费观看| 色噜噜狠狠色综合免费视频| 免费亚洲视频在线观看| 国产成人精品亚洲一区| 国产成人综合亚洲一区| 特级毛片免费播放| yy一级毛片免费视频| 成人网站免费大全日韩国产| a视频免费在线观看| 香蕉免费一区二区三区| 91精品导航在线网址免费| free哆啪啪免费永久|