關於URL編碼(轉載)

原文地址:http://800bu.blog.163.com/blog/static/24724270201011213738952/?fromdm&fromSearch&isFromSearchEngine=yes

http header在線查看工具:http://web-sniffer.net/

一、問題的由來

URL就是網址,只要上網,就一定會用到。

關於URL編碼(轉載) - 800bu - {800Bu}

一般來說,URL只能使用英文字母、阿拉伯數字和某些標點符號,不能使用其他文字符號。因爲網絡標準RFC 1738做了硬性規定:

"...Only alphanumerics [0-9a-zA-Z], the special characters "$-_.+!*'()," [not including the quotes - ed], and reserved characters used for their reserved purposes may be used unencoded within a URL."

“只有字母和數字[0-9a-zA-Z]、一些特殊符號“$-_.+!*'(),”[不包括雙引號]、以及某些保留字,纔可以不經過編碼直接用於URL。”

這意味着,如果URL中有漢字,就必須編碼後使用。

但是麻煩的是,RFC 1738沒有規定具體的編碼方法,交給應用程序自己決定。這導致“URL編碼”成爲了一個混亂的領域。下面我們就來看看,它到底是怎麼實現的。

二、編碼方法:網址路徑

讓我們做幾個試驗,觀察瀏覽器是怎麼對URL編碼的。

打開IE(我用的是8.0版),輸入網址“http://zh.wikipedia.org/wiki/春節”。注意,“春節”這兩個字此時是網頁路徑的一部分。(後面將看到,如果它出現在查詢字符串的部分,將是另一種編碼方式。)

關於URL編碼(轉載) - 800bu - {800Bu}

查看HTTP Head,會發現IE實際查詢的網址是“http://zh.wikipedia.org/wiki/%E6%98%A5%E8%8A%82”。也就是說,IE自動將“春節”編碼成了“%E6%98%A5%E8%8A%82”。

關於URL編碼(轉載) - 800bu - {800Bu}

我們知道,“春”和“節”的utf-8編碼分別是“E6 98 A5”和“E8 8A 82”,因此,“%E6%98%A5%E8%8A%82”就是按照順序,在每個字節前加上%而得到的。(具體的轉碼方法,請參考我寫的《字符編碼筆記》。)

在Firefox中測試,也得到了同樣的結果。因此,結論一就是,網址路徑的編碼,用的是utf-8編碼。

三、編碼方法:查詢字符串

繼續做試驗。在IE中輸入網址“http://www.baidu.com/s?wd=春節”。注意,“春節”這兩個字此時屬於查詢字符串,不屬於網址路徑。

關於URL編碼(轉載) - 800bu - {800Bu}

查看HTTP Head,會發現IE將“春節”轉化成了一個亂碼。

關於URL編碼(轉載) - 800bu - {800Bu}

切換到十六進制方式,才能清楚地看到,“春節”被轉成了“B4 BA BD DA”。

關於URL編碼(轉載) - 800bu - {800Bu}

我們知道,“春”和“節”在GB2312編碼(我的操作系統Windows XP 中文版的默認編碼)中分別是“B4 BA”和“BD DA”。因此,IE實際上就是將查詢字符串,以其GB2312編碼的格式發送出去。

Firefox的處理方法,略有不同。它發送的HTTP Head是“wd=%B4%BA%BD%DA”。也就是說,同樣採用GB2312編碼,但是在每個字節前加上了%。

關於URL編碼(轉載) - 800bu - {800Bu}

因此,結論二就是,查詢字符串的編碼,用的是操作系統的默認編碼。

四、編碼方法:Get和Post

前面說的是直接輸入網址的情況,但是更常見的情況是,在已打開的網頁上,直接用Get或Post方法發出HTTP請求。

根據臺灣中興大學呂瑞麟老師的試驗,這時的編碼方法由網頁的編碼決定,也就是由HTML源碼中字符集的設定決定。

 

如果上面這一行最後的charset是UTF-8,則URL就以UTF-8編碼;如果是GB2312,URL就以GB2312編碼。

舉例來說,百度是GB2312編碼,Google是UTF-8編碼。因此,從它們的搜索框中搜索同一個詞“春節”,生成的查詢字符串是不一樣的。

百度生成的是%B4%BA%BD%DA,這是GB2312編碼。

關於URL編碼(轉載) - 800bu - {800Bu}

Google生成的是%E6%98%A5%E8%8A%82,這是UTF-8編碼。

關於URL編碼(轉載) - 800bu - {800Bu}

因此,結論三就是,GET和POST方法的編碼,用的是網頁的編碼。

五、Javascript函數:escape()

爲了方便編碼,Javascript語言從一開始就提供了escape()函數。

但是實際上,這個函數不能直接用於URL編碼。因爲它返回的不是UTF-8編碼,而是Unicode編碼,比如“春節”的返回結果是%u6625%u8282。

關於URL編碼(轉載) - 800bu - {800Bu}

具體來說,它的規則是,除了ASCII字母、數字、標點符號“@ * _ + - . /”以外,其他所有字符都會被編碼。在?到?之間的符號——也就是前256個符號——被轉成%xx的形式,其餘符號被轉成%uxxxx的形式,其中的xx爲unicode編碼值。它對應的解碼函數是unescape()。

因此,“Hello World”的escape()編碼就是“Hello%20World”。

關於URL編碼(轉載) - 800bu - {800Bu}

這裏有兩個地方需要注意。

首先,Javascript內部的所有字符,都以unicode碼儲存。所以,無論網頁的原始編碼是什麼,一旦被Javascript編碼,就都變爲unicode。

關於URL編碼(轉載) - 800bu - {800Bu}

其次,escape()不對“+”編碼。但是我們知道,在用戶提交的表單字段中,如果有空格,則會被轉化爲+字符。服務器處理數據的時候,會把+號處理成空格。由於這個缺陷,escape方法並不能正確地處理表單數據。ECMAScript v3已經正式廢除了escape(),建議使用其他函數取代。

六、Javascript函數:encodeURI()

encodeURI()是Javascript中真正用來對URL編碼的函數。

它着眼於對URL進行整體編碼,因此除了常見的標點符號以外,對其他一些在網址中有特殊含義的符號“; / ? : @ & = + $ , #”,也不進行編碼。

編碼時,它返回utf-8編碼,每個字節前加上%。

關於URL編碼(轉載) - 800bu - {800Bu}

它對應的解碼函數是decodeURI()。

關於URL編碼(轉載) - 800bu - {800Bu}

需要注意的是,它不對單引號'編碼。

七、Javascript函數:encodeURIComponent()

這個函數與encodeURI()的區別是,只對URL的某一部分單獨編碼,而不對整體編碼。

因此,“; / ? : @ & = + $ , #”,這些在encodeURI()中不被編碼的符號,在encodeURIComponent()中統統會被編碼。至於具體的編碼方法,兩者是一樣。

關於URL編碼(轉載) - 800bu - {800Bu}

它對應的解碼函數是decodeURIComponent()。

(完)

發佈了148 篇原創文章 · 獲贊 8 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章