URL 編碼


HTTP 請求參數,必須使用請求參數名稱與請求參數值,中間以等號(=)表示成對關係,現在問題來了,如果請求參數值本身包括 = 符號怎麼辦?又或許想發送的請求參數值是「https://openhome.cc」這個值呢?假設是 GET 請求,不能直接這麼在網址列上鍵入:

https://openhome.cc/register?url=https://openhome.cc

在 URI 的規範中定義了一些保留字元(Reserved character),像是 :/?&=@% 等字元,在 URI 中都有它的作用,如果要在請求參數上表達 URI 中的保留字元,必須在 % 字元之後以十六進位數值表示方式,來表示該字元的八個位元數值。

例如,: 字元真正儲存時的八個位元為 00111010,用十六進位數值來表示則為 3A,所以必須使用 %3A 來表示 :/字元儲存時的八個位元為 00101111,用十六進位表示則為 2F,所以必須使用 %2F 來表示 / 字元,想發送的請求參數值是「https://openhome.cc」的話,必須使用以下格式:

https://openhome.cc/register?url=https%3A%2F%2Fopenhome.cc

這是 URI 規範中的百分比編碼(Percent-Encoding),也就是俗稱的 URI 編碼或 URL 編碼。如果想得知,某個字元的 URL 編碼為何,在 Java 中可以使用 java.net.URLEncoder 類別的靜態 encode() 方法(相對地,要解碼則是使用 java.net.URLDecoder 的靜態 decode() 方法)。例如:

String text = URLEncoder.encode("https://openhome.cc ", "ISO-8859-1");

知道這些有什麼用?例如,你想給某人一段 URL,讓他可以直接點選就可以連到你想要讓他看到的網頁,你貼給他的 URL 在請求參數部份就要注意 URL 編碼。

不過在 URI 之前,HTTP 在 GET、POST 時也對保留字作了規範,這與 URI 規範的保留字有所差別,其中一個差別就是在 URI 規範中,空白字元是編碼為 %20,而在 HTTP 規範中空白是編碼為 +java.net.URLEncoder 類別的靜態方法 encode() 產生的字串,空白字元就是編碼為 +

另一個差別就是,URI 規範的 URL編 碼,針對的是字元 UTF-8 編碼的八個位元數值,如果請求參數都是 ASCII 字元,那沒什麼問題,因為在 UTF-8 編碼在 ASCII 字元的編碼部份是相容的,也就是使用一個位元組,編碼方式就如先前所述。

但在非 ASCII 字元方面,例如中文,在 UTF-8 的編碼下,會使用三個位元組來表示。例如「林」這個字在 UTF-8 編碼下的三個位元組,對應至十六進位 數值表示就是 E6、9E、97,所以在 URI 規範下,請求參數中要包括「林」這個中文,表示方式就是 %E6%9E%97。例如:

https://openhome.cc/register?lastName=%E6%9E%97

OK!有些人會直接打開瀏覽器鍵入以下的內容,告訴我:「URL 也可以直接打中文啊!」

URL 編碼

不過可以將網址列複製,貼到純文字檔案中,就會看到 URI 編碼的結果,這其實是現在的瀏覽器很聰明,會自動將上述的 URI 編碼顯示為中文。無論如何,在 URI 規範上若如上發送請求參數,伺服端處理請求參數時,必須使用 UTF-8 編碼來取得正確的「林」字元。

然而在 HTTP 規範下的 URL 編碼,並不限使用 UTF-8,例如在一個 BIG5 網頁中,若表單若使用 GET 發送「林」這個中文字,則網址列會出現:

https://openhome.cc/register?lastName=%AA%4C

這是因為「林」這個中文字的 BIG5 編碼為兩個位元組,以十六進位表示的話,則分別為 AA、4C,如果透過表單發送,由於網頁是 BIG5 編碼, 則瀏覽器會自動將「林」編碼為 %AA%4C,伺服端處理請求參數時,就必須指定 BIG5 編碼,以取得正確的「林」中文字元。

若是 %AA%4C,由於單獨看 %4C 的話,代表著字元 L,瀏覽器也可以發送 %AAL

若使用 java.net.URLEncoder 類別的靜態 encode() 方法來作這個編碼的動作,可以如下得到 %AA%4C的結果:

String text = URLEncoder.encode("林 ", "BIG5");

同理可推,如果網頁是 UTF-8 編碼,而你透過表單發送,則瀏覽器會自動將「林」編碼為 %E6%9E%97。若使用 java.net.URLEncoder 類別的靜態 encode() 方法,則如下得到 %E6%9E%97 的結果:

String text = URLEncoder.encode("林", "UTF-8");

這些是對於 URL 編碼的必要認識,當你發送表單、使用 Tomcat 等容器或是運用 Ajax 等技術時,都要有這個基本認識,才能進一步處理遇到的亂碼問題。