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 也可以直接打中文啊!」
不過可以將網址列複製,貼到純文字檔案中,就會看到 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 等技術時,都要有這個基本認識,才能進一步處理遇到的亂碼問題。