細談 URL 編碼
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: 國立中興大學資管系呂瑞麟
請勿轉貼
看其他教材
在這十幾年的教學生涯中,不論在教學或是指導學生做專題的過程中,總是 不斷的跟學生解釋為什麼在網頁上輸入中文(Big5 或者 UTF-8),但是處理 的結果(可能網頁的呈現或者資料庫的存取)卻老是會出現亂碼。因為我有 寫網頁教材的習慣,所以總是寫一寫就叫學生自己去看,而曾經探討過這個 議題的有:資料處理入門(這是使用 JDK 1.2 版以前所需要解決的方式)、Java Servlet 入門(這是第一次處理網頁的中文資料的解決方式)、MySQL Server 簡介(這是針對將 Big5 資料存入 MySQL,並將 MySQL 的資料正確轉回 Big5 的 解決方式)、以及 由 XMLHttpRequest 送出中文資料給 Tomcat(這是針對 XMLHttpRequest 傳送中文給 Tomcat 的解決方式)。 最近有一次跟學生聊天,他們提到網頁內容的編碼方式是利用 UTF-8 的方式, 處理的結果卻不盡相同,於是讓我想要重新做一次(儘可能)完整的探討,來細細的說明 為什麼網頁中文資料的傳送有那麼樣的"曲折離奇"!
在參考了幾篇文章之後,我列出最有幫助的兩篇:
- Brian Wilson, URL Encoding
- John O'Conner, Character Conversions from Browser to Database, Sun Devloper Network, 01/2006.
知道了這些事實之後,我們先把我們的測試環境描述一下:在瀏覽器的部分,我們 使用 Firefox 3.x 和 IE 8.x;後端伺服器的部分,我們使用 Tomcat 5.5.x, 後端程式是 Java 的 servlet。如果你使用的環境不同,應該也可以用類似的方法 來測試,並找尋你的解決方法。[註:2014 年 10 月將系統的 Tomcat 升級到 7.0.x 版,由於其中一個測試平台是在 Debian Wheezy 上的,而它的 Tomcat 設定是將編碼預設為 UTF-8,這可以從 server.xml 中是否包含下列敘述而定。想要測試這篇文章的範例,建議將 URIEncoding="UTF-8" 移除,並重新啟動 Tomcat,因為從 Apache 下載的 Tomcat 7/8 都沒有這個設定。]
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" URIEncoding="UTF-8" redirectPort="8443" />
網頁的內容,我們採用兩種主要的編碼:Big5 和 UTF-8。由於我習慣上都是 使用 Microsoft Windows 的記事本(也就是 notepad.exe),所以我要提醒一下 讀者:使用 notepad 來儲存網頁內容的時候,預設的編碼方式就是 Big5; 如果你想產生 UTF-8 的內容,請記得在儲存網頁的時候,選擇 UTF-8 的 編碼(如下圖所示)。如果你使用的是其他的文字編輯器,請再測試前先確認 網頁儲存時所使用的編碼是什麼,然後做必要的調整。
<html> <head> <meta http-equiv="Content-Type" content="text/html;charset=Big5"> <title>測試劉覽器 URL 編碼</title> </head> <body> <h2>測試劉覽器 URL 編碼</h2> <h3>HTML 以 Big5 編碼,呼叫 EchoBig5</h3> <form method="GET" action="/xml/servlet/EchoBig5"> <input type="text" value="老呂" name="data"> <input type="submit" value="確定"> </form> </body> </html>
讀者也可以使用一般的 16 進位編輯器來確認"老呂"就是由 A6 D1 A7 66; 我們使用的是 notepad++ 以及其 16 進位編輯器的外掛程式,顯示"老呂"畫面(highlighted) 如下:
一般畫面 | 16 進位畫面 |
---|---|
到目前為止,我們已經清楚了瀏覽器是如何進行 URL 編碼,可是編碼後的資料 是如何被伺服器所處理呢?就之前所說的事實,這部份是沒有編準的,所以我們 就以我們所使用的伺服器 Tomcat 5.5.x 版來說明。在預設的情形下,Tomcat 無法以 Big5 的方式來解讀從瀏覽器傳過來的 URL,而是以 ISO-8859-1 的編碼 方式來解讀。為了確認這個說法,我們設計了以下的程式,也就是剛剛 <form> 標籤中的 EchoBig5:
01 import javax.servlet.*; 02 import javax.servlet.http.*; 03 import java.io.*; 04 05 public class EchoBig5 extends HttpServlet { 06 public void doGet(HttpServletRequest req, HttpServletResponse res) 07 throws ServletException, IOException { 08 PrintWriter output; 09 10 res.setContentType("text/html;charset=Big5"); 11 output = res.getWriter(); 12 13 StringBuffer buf = new StringBuffer(); 14 buf.append("<html><head><title>\n"); 15 buf.append("Echo Big5\n"); 16 buf.append("</title></head><body>\n"); 17 18 String data = req.getParameter("data"); 19 String orig = data.length() + " "; 20 for(int i=0; i<data.length(); i++) { 21 int ch = (int)data.charAt(i); 22 orig = orig + "%" + Integer.toHexString(ch); 23 } 24 String out1 = new String(data.getBytes("ISO-8859-1"), "Big5"); 25 26 buf.append("<h1>String: " + data + "</h1>\n"); 27 buf.append("<h1>Hex Numbers: " + orig + "</h1>\n"); 28 buf.append("<h1>Big5 Encoded: " + out1 + "</h1>\n"); 29 buf.append("</body></html>\n"); 30 output.println(buf.toString()); 31 32 output.close(); 33 } 34 }
由於 Tomcat 將 A6 D1 A7 66 視為 ISO-8859-1 碼,因此要能夠正確的 顯示其 Big5 的內容,我們必須藉助 Java 的 String 轉碼功能;在第 24 行的 地方,程式先把 data 字串依據 ISO-8859-1 碼的方式取出並形成一個 字元陣列,然後利用該陣列來建構一個字串物件,而轉碼的方式是把其 視為 Big5,而結果就是 out1 字串,該字串在第 28 行中輸出,也就是 執行畫面中第三行的結果。
練習題: 既然 Tomcat 是使用 ISO-8859-1 的方式編、解碼,那麼 我們的網頁內容直接使用 ISO-8859-1 來寫,可不可以?
繼續閱讀:Part II
Written by: 國立中興大學資管系呂瑞麟
目前最新版的notepad++,版本號為6.2.2,已不支援Hex Edit外掛了…手動下載到plugin資料夾也沒用。
回覆刪除謝謝提供資訊,你可以試著下載舊版的。其實這份文件的主要目的在於概念的描述以及驗證方式,使用的工具只要能看得到 16 進位的值即可。
回覆刪除不错,谢谢分享。
回覆刪除