爲何要對url進行encode php
發現如今幾乎全部的網站都對url中的漢字和特殊的字符,進行了urlencode操做,也就是:html
http://hi.baidu.com/%BE%B2%D0%C4%C0%CF%C8%CB/creat/blog/java
這個樣子,中間%形式的,確定就是個人登陸用戶名稱了吧。程序員
爲何對這些字符進行了u的編碼形式,是爲了字符編碼(gbk、utf8)仍是爲了避免出現特殊的字符在url中?都知道要轉,可是轉了的真正好處呢。查看了網上的不少資料,也沒有找到更加準確的說法。web
url轉義其實也只是爲了符合url的規範而已。由於在標準的url規範中中文和不少的字符是不容許出如今url中的。ajax
看一下php的urlencode的說明了。apache
urlencode — 編碼 URL 字符串編程
string urlencode ( string $str )瀏覽器
返回字符串,此字符串中除了 -_. 以外的全部非字母數字字符都將被替換成百分號(%)後跟兩位十六進制數,空格則編碼爲加號(+)。此編碼與 WWW 表單 POST 數據的編碼方式是同樣的,同時與 application/x-www-form-urlencoded 的媒體類型編碼方式同樣。因爲歷史緣由,此編碼在將空格編碼爲加號(+)方面與 RFC1738 編碼(參見 rawurlencode())不一樣。此函數便於將字符串編碼並將其用於 URL 的請求部分,同時它還便於將變量傳遞給下一頁。安全
標準的英文說明是:
"...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."
那哪些字符是須要轉化的呢?
1. ASCII 的控制字符
這些字符都是不可打印的,天然須要進行轉化。
2. 一些非ASCII字符
這些字符天然是非法的字符範圍。轉化也是理所固然的了。
3. 一些保留字符
很明顯最多見的就是「&」了,這個若是出如今url中了,那你認爲是url中的一個字符呢,仍是特殊的參數分割用的呢?
4. 就是一些不安全的字符了。
例如:空格。爲了防止引發歧義,須要被轉化爲「+」。
明白了這些,也就知道了爲何須要轉化了,而轉化的規則也是很簡單的。
按照每一個字符對應的字符編碼,不是符合咱們範圍的,通通的轉化爲%的形式也就是了。天然也是16進制的形式。
和字符編碼無關
經過urlencode的轉化規則和目的,咱們也很容易的看出,urleocode是基於字符編碼的。一樣的一個漢字,不一樣的編碼類型,確定對應不一樣的urleocode的串。gbk編碼的有gbk的encode結果。
apache等服務器,接受到字符串後,能夠進行decode,可是仍是沒法解決編碼的問題。編碼問題,仍是須要靠約定或者字符編碼的判斷解決。
所以,urleocode只是爲了url中一些非ascii字符,能夠正確無誤的被傳輸,至於使用哪一種編碼,就不是eocode所關心和解決的問題了。
編碼問題,不是urlencode所要解決的。
轉自:http://apps.hi.baidu.com/share/detail/32230450
參考資料:
http://www.blooberry.com/indexdot/html/topics/urlencoding.htm
http://cn.php.net/manual/zh/function.urlencode.php
問題來源:
正在研究一個程序,輸入一個關鍵字,可以把這個關鍵字發送到Google,yahoo等搜索引擎,進行搜索,而後打開結果網頁。原理很簡單。好比在Google搜索China,搜索結果頁面的URL就是「http://www.google.com/search?hl=zh-CN&q=China&lr=」。只要替換紅顏色的內容,就能夠按照不一樣的關鍵字搜索。
可是若是關鍵字是中文,就會出現問題。好比在google搜索「中國」,Url是「http://www.google.com/search?hl=zh-CN&newwindow=1&q=%E4%B8%AD%E5%9B%BD&lr=」。漢字「中國」被按照UTF-8的格式進行編碼。
不只漢字進行編碼,一些特殊字符也會進行編碼。好比搜索「C#」,URL是「http://www.google.com/search?hl=zh-CN&newwindow=1&q=C%23&lr=」。
通常來講,國外的網站都是按照UTF-8編碼,而「百度」是按照「GB2312」進行編碼的。好比搜索「中國」,URL是「http://www.baidu.com/s?wd=%D6%D0%B9%FA&cl=3」
咱們對比一下:C#中國的編碼
編碼 | 結果 | 網站 |
UTF-8 | C%23%E4%B8%AD%E5%9B%BD | |
GB2312 | C%23%D6%D0%B9%FA | BaiDu |
總結:
UTF-8中,一個漢字對應三個字節,GB2312中一個漢字佔用兩個字節。
不論何種編碼,字母數字都不編碼,特殊符號編碼後佔用一個字節。
開始編程:
public static string UrlEncode(string str, string encode)
{
int factor;
if (encode == "UTF-8")
factor = 3;
if (encode == "GB2312")
factor = 2;
//不須要編碼的字符
string okChar = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-*@";
System.Text.Encoder encoder = System.Text.Encoding.GetEncoding(encode).GetEncoder();
char[] c1 = str.ToCharArray();
System.Text.StringBuilder sb = new System.Text.StringBuilder();
//一個字符一個字符的編碼
for (int i = 0; i < c1.Length; i++)
{
//不須要編碼
if (okChar.IndexOf(c1[i]) > -1)
sb.Append(c1[i]);
else
{
byte[] c2 = new byte[factor];
int charUsed, byteUsed; bool completed;
encoder.Convert(c1, i, 1, c2, 0, factor, true, out charUsed, out byteUsed, out completed);
foreach (byte b in c2)
{
if (b != 0)
sb.AppendFormat("%{0:X}", b);
}
}
}
return sb.ToString().Trim();
}
後來發現更簡單的方法。
//按照UTF-8進行編碼
string tempSearchString1 = System.Web.HttpUtility.UrlEncode("C#中國");
//按照GB2312進行編碼
string tempSearchString2 = System.Web.HttpUtility.UrlEncode("C#中國",System.Text.Encoding.GetEncoding("GB2312"));
你們直接用第二種方法就好了。
由於第一種是本身好不容易編出來的,貼在這裏留個記念。
1、問題的由來
URL就是網址,只要上網,就必定會用到。
通常來講,URL只能使用英文字母、阿拉伯數字和某些標點符號,不能使用其餘文字和符號。好比,世界上有英文字母的網址"http://www.abc.com",可是沒有希臘字母的網址"http://www.aβγ.com"(讀做阿爾法-貝塔-伽瑪.com)。這是由於網絡標準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編碼"到底有多混亂。我會依次分析四種不一樣的狀況,在每一種狀況中,瀏覽器的URL編碼方法都不同。把它們的差別解釋清楚以後,我再說如何用Javascript找到一個統一的編碼方法。
2、狀況1:網址路徑中包含漢字
打開IE(我用的是8.0版),輸入網址"http://zh.wikipedia.org/wiki/春節"。注意,"春節"這兩個字此時是網址路徑的一部分。
查看HTTP請求的頭信息,會發現IE實際查詢的網址是"http://zh.wikipedia.org/wiki/%E6%98%A5%E8%8A%82"。也就是說,IE自動將"春節"編碼成了"%E6%98%A5%E8%8A%82"。
咱們知道,"春"和"節"的utf-8編碼分別是"E6 98 A5"和"E8 8A 82",所以,"%E6%98%A5%E8%8A%82"就是按照順序,在每一個字節前加上%而獲得的。(具體的轉碼方法,請參考我寫的《字符編碼筆記》。)
在Firefox中測試,也獲得了一樣的結果。因此,結論1就是,網址路徑的編碼,用的是utf-8編碼。
3、狀況2:查詢字符串包含漢字
在IE中輸入網址"http://www.baidu.com/s?wd=春節"。注意,"春節"這兩個字此時屬於查詢字符串,不屬於網址路徑,不要與狀況1混淆。
查看HTTP請求的頭信息,會發現IE將"春節"轉化成了一個亂碼。
切換到十六進制方式,才能清楚地看到,"春節"被轉成了"B4 BA BD DA"。
咱們知道,"春"和"節"的GB2312編碼(個人操做系統"Windows XP"中文版的默認編碼)分別是"B4 BA"和"BD DA"。所以,IE實際上就是將查詢字符串,以GB2312編碼的格式發送出去。
Firefox的處理方法,略有不一樣。它發送的HTTP Head是"wd=%B4%BA%BD%DA"。也就是說,一樣採用GB2312編碼,可是在每一個字節前加上了%。
因此,結論2就是,查詢字符串的編碼,用的是操做系統的默認編碼。
4、狀況3:Get方法生成的URL包含漢字
前面說的是直接輸入網址的狀況,可是更常見的狀況是,在已打開的網頁上,直接用Get或Post方法發出HTTP請求。
根據臺灣中興大學呂瑞麟老師的試驗,這時的編碼方法由網頁的編碼決定,也就是由HTML源碼中字符集的設定決定。
<meta http-equiv="Content-Type" content="text/html;charset=xxxx">
若是上面這一行最後的charset是UTF-8,則URL就以UTF-8編碼;若是是GB2312,URL就以GB2312編碼。
舉例來講,百度是GB2312編碼,Google是UTF-8編碼。所以,從它們的搜索框中搜索同一個詞"春節",生成的查詢字符串是不同的。
百度生成的是%B4%BA%BD%DA,這是GB2312編碼。
Google生成的是%E6%98%A5%E8%8A%82,這是UTF-8編碼。
因此,結論3就是,GET和POST方法的編碼,用的是網頁的編碼。
5、狀況4:Ajax調用的URL包含漢字
前面三種狀況都是由瀏覽器發出HTTP請求,最後一種狀況則是由Javascript生成HTTP請求,也就是Ajax調用。仍是根據呂瑞麟老師的文章,在這種狀況下,IE和Firefox的處理方式徹底不同。
舉例來講,有這樣兩行代碼:
url = url + "?q=" +document.myform.elements[0].value; // 假定用戶在表單中提交的值是"春節"這兩個字
http_request.open('GET', url, true);
那麼,不管網頁使用什麼字符集,IE傳送給服務器的老是"q=%B4%BA%BD%DA",而Firefox傳送給服務器的老是"q=%E6%98%A5%E8%8A%82"。也就是說,在Ajax調用中,IE老是採用GB2312編碼(操做系統的默認編碼),而Firefox老是採用utf-8編碼。這就是咱們的結論4。
6、Javascript函數:escape()
好了,到此爲止,四種狀況都說完了。
假定前面你都看懂了,那麼此時你應該會感到很頭痛。由於,實在太混亂了。不一樣的操做系統、不一樣的瀏覽器、不一樣的網頁字符集,將致使徹底不一樣的編碼結果。若是程序員要把每一種結果都考慮進去,是否是太恐怖了?有沒有辦法,可以保證客戶端只用一種編碼方法向服務器發出請求?
回答是有的,就是使用Javascript先對URL編碼,而後再向服務器提交,不要給瀏覽器插手的機會。由於Javascript的輸出老是一致的,因此就保證了服務器獲得的數據是格式統一的。
Javascript語言用於編碼的函數,一共有三個,最古老的一個就是escape()。雖然這個函數如今已經不提倡使用了,可是因爲歷史緣由,不少地方還在使用它,因此有必要先從它講起。
實際上,escape()不能直接用於URL編碼,它的真正做用是返回一個字符的Unicode編碼值。好比"春節"的返回結果是%u6625%u8282,也就是說在Unicode字符集中,"春"是第6625個(十六進制)字符,"節"是第8282個(十六進制)字符。
它的具體規則是,除了ASCII字母、數字、標點符號"@ * _ + - . /"之外,對其餘全部字符進行編碼。在\u0000到\u00ff之間的符號被轉成%xx的形式,其他符號被轉成%uxxxx的形式。對應的解碼函數是unescape()。
因此,"Hello World"的escape()編碼就是"Hello%20World"。由於空格的Unicode值是20(十六進制)。
還有兩個地方須要注意。
首先,不管網頁的原始編碼是什麼,一旦被Javascript編碼,就都變爲unicode字符。也就是說,Javascipt函數的輸入和輸出,默認都是Unicode字符。這一點對下面兩個函數也適用。
其次,escape()不對"+"編碼。可是咱們知道,網頁在提交表單的時候,若是有空格,則會被轉化爲+字符。服務器處理數據的時候,會把+號處理成空格。因此,使用的時候要當心。
7、Javascript函數:encodeURI()
encodeURI()是Javascript中真正用來對URL編碼的函數。
它着眼於對整個URL進行編碼,所以除了常見的符號之外,對其餘一些在網址中有特殊含義的符號"; / ? : @ & = + $ , #",也不進行編碼。編碼後,它輸出符號的utf-8形式,而且在每一個字節前加上%。
它對應的解碼函數是decodeURI()。
須要注意的是,它不對單引號'編碼。
8、Javascript函數:encodeURIComponent()
最後一個Javascript編碼函數是encodeURIComponent()。與encodeURI()的區別是,它用於對URL的組成部分進行個別編碼,而不用於對整個URL進行編碼。
所以,"; / ? : @ & = + $ , #",這些在encodeURI()中不被編碼的符號,在encodeURIComponent()中通通會被編碼。至於具體的編碼方法,二者是同樣。
它對應的解碼函數是decodeURIComponent()。
(完)