由 XMLHttpRequest 送出中文資料給 Tomcat
The following examples had been tested on Mozilla's Firefox and Microsoft's IE. The document is provided as is. You are welcomed to use it for non-commercial purpose.Written by: 國立中興大學資管系呂瑞麟
請勿轉貼
看其他教材
在嘗試 Dojo 和 Yahoo! User Interface Library (YUI) 的時候,才突然發現之前的
AJAX 範例都沒有從 XMLHttpRequest 傳送中文的資料給遠端的 Tomcat servlet。
而發現的原因在於為 Dojo 和 YUI 所寫的程式中,其中一個範例是由 browser 送出
一個中文的(Big5)欄位資料到遠端的 Tomcat servlet 處理,而處理的結果
卻是亂碼。這樣子一來就打亂了我的休假,連續兩個晚上測到凌晨一、兩點
(對一個老人來說,是很大的折磨)。這兩天找了不少資料,目前以
- John O'Conner, Character Conversions from Browser to Database, Sun Devloper Network, 01/2006.
- Greg Murray, AJAX I18n with Java, Greg Murray's Blog, 03/2006.
- 由 XMLHttpRequest 送出去的 URL:如果 URL 包含 Big5 的資料,XMLHttpRequest 會不會 encode,而且又是以何種方式 encode?
- server 是如何解讀收到的 URL:目前知道 Tomcat (我的主要 servlet 開發 平台)是採用 ISO-8859-1 編碼方式來接收,因此解碼的方式可以用 ISO-8859-1 來進行。但是,如果 browser 送過來的資料是以 UTF-8 編碼,那要怎麼辦呢?
- IE 6.x/7.x:
- 若 Javascript 對中文資料 encodeURIComponent(),則 servlet 需要對接收到的資料先以 ISO-8859-1 解出來之後,以 UTF-8 編碼出來。
- 若 Javascript 不對中文資料進行 encodeURIComponent(),則 servlet 需要對接收到的資料先以 ISO-8859-1 解出來之後,以 Big5 編碼出來。
- Firefox 1.5.x 或者新版本:不論 browser 是否對中文資料 encodeURIComponent(),servlet 需要對接收到的資料 先以 ISO-8859-1 解出來之後,以 UTF-8 編碼出來。
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=Big5"> <script type="text/javascript" language="javascript"> function makeRequest(url) { var http_request = false; if (window.XMLHttpRequest) { // Mozilla, Safari,... http_request = new XMLHttpRequest(); } else if (window.ActiveXObject) { // IE try { http_request = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { http_request = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) {} } } if (!http_request) { alert('Giving up :( Cannot create an XMLHTTP instance'); return false; } // 定義事件處理函數為 alterContents() http_request.onreadystatechange = function() { alertContents(http_request); }; // IE 6.x 和 Firefox 1.5.x 皆要 encodeURI() url = url + "?name=" + encodeURIComponent(document.myform.elements[0].value); http_request.open('GET', url, true); http_request.send(null); } function alertContents(http_request) { if (http_request.readyState == 4) { if (http_request.status == 200) { var mesg = http_request.responseText; alert(mesg); } else { alert('There was a problem with the request.'); } } } </script> </head> <body> <form name="myform"> 姓名: <input type="text" name="name"></input> <input type="button" value="OK" onClick="makeRequest('適當的 servlet URL');"></input> </form> </body> </html>
import javax.servlet.*; import javax.servlet.http.*; import java.io.*; public class Hello extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/plain;charset=UTF-8"); PrintWriter output = res.getWriter(); String msg = req.getParameter("name"); msg = new String(msg.getBytes("ISO-8859-1"), "UTF-8"); StringBuffer buf = new StringBuffer(); buf.append("Hello " + msg); buf.append(" , 歡迎使用 AJAX"); output.println(buf.toString()); output.close(); } }
瀏覽器中的中文 --經過 encodeURIComponent() 轉碼(這部份的程式碼是為了執行跟所有瀏覽器預設的動作) --經過 Tomcat 編碼 --> ISO-8859-1 (Tomcat 無法知道客戶端送過來的編碼為何,因此它會先 decodeURI() 然後把資料以 ISO-8859-1 編碼) --經過 servlet 的 getBytes("ISO-8859-1") 以 ISO8859-1 的方式解讀 URL 的資料 --再經過 new String(..., "需要的編碼") 將資料從 ISO-8859-1 的編碼轉換成需要的編碼;在這個範例中,由於程式碼中的中文是以 UTF-8 編碼(我在最近一次升級伺服器之後,將系統預設編碼設定成 UTF-8),所以回傳的資料編碼為 UTF-8(程式碼中的 setContentType() 可以看得出來)。個人心得: 雖然非常多的專家都認為應該將 Linux 的預設編碼設定為 UTF-8 (也就是 zh_TW.UTF-8),但是經過一段時間的使用之後,我還真的 有點後悔,原因很簡單:我的客戶端作業系統是 XP Professional 繁體中文版, 而且之前開發的一些程式(內含中文)都是以 XP 的預設編碼來做的,也就是 大五碼(Big5),在這樣的環境下,不斷的注意編碼的一致性實在很痛苦,所以 我個人建議還是將 Linux 的預設編碼設定為 Big5 (也就是 zh_TW.Big5) 會比較方便。
Written by: 國立中興大學資管系呂瑞麟
沒有留言:
張貼留言