URL編碼

一僵控、問題的由來

URL就是網(wǎng)址,只要上網(wǎng)刮刑,就一定會用到喉祭。

bg2010021101.jpg

一般來說,URL只能使用英文字母雷绢、阿拉伯數(shù)字和某些標點符號泛烙,不能使用其他文字和符號。比如翘紊,世界上有英文字母的網(wǎng)址"http://www.abc.com"蔽氨,但是沒有希臘字母的網(wǎng)址"http://www.aβγ.com"(讀作阿爾法-貝塔-伽瑪.com)。這是因為網(wǎng)絡標準RFC 1738做了硬性規(guī)定:

"...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."

"只有字母和數(shù)字[0-9a-zA-Z]帆疟、一些特殊符號"$-_.+!*'(),"[不包括雙引號]鹉究、以及某些保留字,才可以不經(jīng)過編碼直接用于URL踪宠。"

這意味著自赔,如果URL中有漢字,就必須編碼后使用柳琢。但是麻煩的是绍妨,RFC 1738沒有規(guī)定具體的編碼方法,而是交給應用程序(瀏覽器)自己決定柬脸。這導致"URL編碼"成為了一個混亂的領域他去。

下面就讓我們看看,"URL編碼"到底有多混亂倒堕。我會依次分析四種不同的情況灾测,在每一種情況中,瀏覽器的URL編碼方法都不一樣垦巴。把它們的差異解釋清楚之后媳搪,我再說如何用Javascript找到一個統(tǒng)一的編碼方法。

二魂那、情況1:網(wǎng)址路徑中包含漢字

打開IE(我用的是8.0版)蛾号,輸入網(wǎng)址"http://zh.wikipedia.org/wiki/春節(jié)"。注意涯雅,"春節(jié)"這兩個字此時是網(wǎng)址路徑的一部分鲜结。

bg2010021102.jpg

查看HTTP請求的頭信息,會發(fā)現(xiàn)IE實際查詢的網(wǎng)址是"http://zh.wikipedia.org/wiki/%E6%98%A5%E8%8A%82"。也就是說精刷,IE自動將"春節(jié)"編碼成了"%E6%98%A5%E8%8A%82"拗胜。

bg2010021103.png

我們知道,"春"和"節(jié)"的utf-8編碼分別是"E6 98 A5"和"E8 8A 82"怒允,因此埂软,"%E6%98%A5%E8%8A%82"就是按照順序,在每個字節(jié)前加上%而得到的纫事。(具體的轉(zhuǎn)碼方法勘畔,請參考我寫的《字符編碼筆記》。)

在Firefox中測試丽惶,也得到了同樣的結(jié)果炫七。所以,結(jié)論1就是钾唬,網(wǎng)址路徑的編碼万哪,用的是utf-8編碼。

三抡秆、情況2:查詢字符串包含漢字

在IE中輸入網(wǎng)址"http://www.baidu.com/s?wd=春節(jié)"奕巍。注意,"春節(jié)"這兩個字此時屬于查詢字符串儒士,不屬于網(wǎng)址路徑的止,不要與情況1混淆。

bg2010021104.jpg

查看HTTP請求的頭信息着撩,會發(fā)現(xiàn)IE將"春節(jié)"轉(zhuǎn)化成了一個亂碼冲杀。

bg2010021105.png

切換到十六進制方式询筏,才能清楚地看到容贝,"春節(jié)"被轉(zhuǎn)成了"B4 BA BD DA"畔况。

bg2010021106.png

我們知道,"春"和"節(jié)"的GB2312編碼(我的操作系統(tǒng)"Windows XP"中文版的默認編碼)分別是"B4 BA"和"BD DA"憋沿。因此,IE實際上就是將查詢字符串沪猴,以GB2312編碼的格式發(fā)送出去辐啄。

Firefox的處理方法,略有不同运嗜。它發(fā)送的HTTP Head是"wd=%B4%BA%BD%DA"壶辜。也就是說,同樣采用GB2312編碼担租,但是在每個字節(jié)前加上了%砸民。

bg2010021107.png

所以,結(jié)論2就是,查詢字符串的編碼岭参,用的是操作系統(tǒng)的默認編碼反惕。

四、情況3:Get方法生成的URL包含漢字

前面說的是直接輸入網(wǎng)址的情況演侯,但是更常見的情況是姿染,在已打開的網(wǎng)頁上,直接用Get或Post方法發(fā)出HTTP請求秒际。

根據(jù)臺灣中興大學呂瑞麟老師的試驗悬赏,這時的編碼方法由網(wǎng)頁的編碼決定,也就是由HTML源碼中字符集的設定決定娄徊。

<meta http-equiv="Content-Type" content="text/html;charset=xxxx">

如果上面這一行最后的charset是UTF-8闽颇,則URL就以UTF-8編碼;如果是GB2312嵌莉,URL就以GB2312編碼进萄。

舉例來說,百度是GB2312編碼锐峭,Google是UTF-8編碼中鼠。因此,從它們的搜索框中搜索同一個詞"春節(jié)"沿癞,生成的查詢字符串是不一樣的援雇。

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

bg2010021109.jpg

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

bg2010021108.jpg

所以蚕涤,結(jié)論3就是筐赔,GET和POST方法的編碼,用的是網(wǎng)頁的編碼揖铜。

五茴丰、情況4:Ajax調(diào)用的URL包含漢字

前面三種情況都是由瀏覽器發(fā)出HTTP請求,最后一種情況則是由Javascript生成HTTP請求天吓,也就是Ajax調(diào)用贿肩。還是根據(jù)呂瑞麟老師的文章,在這種情況下龄寞,IE和Firefox的處理方式完全不一樣汰规。

舉例來說,有這樣兩行代碼:

url = url + "?q=" +document.myform.elements[0].value; // 假定用戶在表單中提交的值是"春節(jié)"這兩個字

http_request.open('GET', url, true);

那么物邑,無論網(wǎng)頁使用什么字符集溜哮,IE傳送給服務器的總是"q=%B4%BA%BD%DA"滔金,而Firefox傳送給服務器的總是"q=%E6%98%A5%E8%8A%82"。也就是說茬射,在Ajax調(diào)用中鹦蠕,IE總是采用GB2312編碼(操作系統(tǒng)的默認編碼),而Firefox總是采用utf-8編碼在抛。這就是我們的結(jié)論4钟病。

六、Javascript函數(shù):escape()

好了刚梭,到此為止肠阱,四種情況都說完了。

假定前面你都看懂了朴读,那么此時你應該會感到很頭痛屹徘。因為,實在太混亂了衅金。不同的操作系統(tǒng)噪伊、不同的瀏覽器、不同的網(wǎng)頁字符集氮唯,將導致完全不同的編碼結(jié)果鉴吹。如果程序員要把每一種結(jié)果都考慮進去,是不是太恐怖了惩琉?有沒有辦法豆励,能夠保證客戶端只用一種編碼方法向服務器發(fā)出請求?

回答是有的瞒渠,就是使用Javascript先對URL編碼良蒸,然后再向服務器提交,不要給瀏覽器插手的機會伍玖。因為Javascript的輸出總是一致的嫩痰,所以就保證了服務器得到的數(shù)據(jù)是格式統(tǒng)一的。

Javascript語言用于編碼的函數(shù)窍箍,一共有三個始赎,最古老的一個就是escape()。雖然這個函數(shù)現(xiàn)在已經(jīng)不提倡使用了仔燕,但是由于歷史原因,很多地方還在使用它魔招,所以有必要先從它講起晰搀。

實際上,escape()不能直接用于URL編碼办斑,它的真正作用是返回一個字符的Unicode編碼值外恕。比如"春節(jié)"的返回結(jié)果是%u6625%u8282杆逗,也就是說在Unicode字符集中,"春"是第6625個(十六進制)字符鳞疲,"節(jié)"是第8282個(十六進制)字符罪郊。

bg2010021110.png

它的具體規(guī)則是,除了ASCII字母尚洽、數(shù)字悔橄、標點符號"@ * _ + - . /"以外,對其他所有字符進行編碼腺毫。在\u0000到\u00ff之間的符號被轉(zhuǎn)成%xx的形式癣疟,其余符號被轉(zhuǎn)成%uxxxx的形式。對應的解碼函數(shù)是unescape()潮酒。

所以睛挚,"Hello World"的escape()編碼就是"Hello%20World"。因為空格的Unicode值是20(十六進制)急黎。

bg2010021111.png

還有兩個地方需要注意扎狱。

首先,無論網(wǎng)頁的原始編碼是什么勃教,一旦被Javascript編碼淤击,就都變?yōu)閡nicode字符。也就是說荣回,Javascipt函數(shù)的輸入和輸出遭贸,默認都是Unicode字符。這一點對下面兩個函數(shù)也適用心软。

bg2010021112.png

其次壕吹,escape()不對"+"編碼。但是我們知道删铃,網(wǎng)頁在提交表單的時候耳贬,如果有空格,則會被轉(zhuǎn)化為+字符猎唁。服務器處理數(shù)據(jù)的時候咒劲,會把+號處理成空格。所以诫隅,使用的時候要小心腐魂。

七、Javascript函數(shù):encodeURI()

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

它著眼于對整個URL進行編碼蛔屹,因此除了常見的符號以外,對其他一些在網(wǎng)址中有特殊含義的符號"; / ? : @ & = + $ , #"豁生,也不進行編碼兔毒。編碼后漫贞,它輸出符號的utf-8形式,并且在每個字節(jié)前加上%育叁。

bg2010021113.png

它對應的解碼函數(shù)是decodeURI()迅脐。

bg2010021114.png

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

八谴蔑、Javascript函數(shù):encodeURIComponent()

最后一個Javascript編碼函數(shù)是encodeURIComponent()。與encodeURI()的區(qū)別是昵骤,它用于對URL的組成部分進行個別編碼树碱,而不用于對整個URL進行編碼。

因此变秦,"; / ? : @ & = + $ , #"成榜,這些在encodeURI()中不被編碼的符號,在encodeURIComponent()中統(tǒng)統(tǒng)會被編碼蹦玫。至于具體的編碼方法赎婚,兩者是一樣。

bg2010021115.png

它對應的解碼函數(shù)是decodeURIComponent()樱溉。

轉(zhuǎn)載自http://www.ruanyifeng.com/blog/2010/02/url_encoding.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末挣输,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子福贞,更是在濱河造成了極大的恐慌撩嚼,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,423評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件挖帘,死亡現(xiàn)場離奇詭異完丽,居然都是意外死亡,警方通過查閱死者的電腦和手機拇舀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,147評論 2 385
  • 文/潘曉璐 我一進店門逻族,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人骄崩,你說我怎么就攤上這事聘鳞。” “怎么了要拂?”我有些...
    開封第一講書人閱讀 157,019評論 0 348
  • 文/不壞的土叔 我叫張陵抠璃,是天一觀的道長。 經(jīng)常有香客問我脱惰,道長搏嗡,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,443評論 1 283
  • 正文 為了忘掉前任枪芒,我火速辦了婚禮彻况,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘舅踪。我一直安慰自己纽甘,他們只是感情好,可當我...
    茶點故事閱讀 65,535評論 6 385
  • 文/花漫 我一把揭開白布抽碌。 她就那樣靜靜地躺著悍赢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪货徙。 梳的紋絲不亂的頭發(fā)上左权,一...
    開封第一講書人閱讀 49,798評論 1 290
  • 那天,我揣著相機與錄音痴颊,去河邊找鬼赏迟。 笑死,一個胖子當著我的面吹牛蠢棱,可吹牛的內(nèi)容都是我干的锌杀。 我是一名探鬼主播,決...
    沈念sama閱讀 38,941評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼泻仙,長吁一口氣:“原來是場噩夢啊……” “哼糕再!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起玉转,我...
    開封第一講書人閱讀 37,704評論 0 266
  • 序言:老撾萬榮一對情侶失蹤突想,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后究抓,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體猾担,經(jīng)...
    沈念sama閱讀 44,152評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,494評論 2 327
  • 正文 我和宋清朗相戀三年漩蟆,在試婚紗的時候發(fā)現(xiàn)自己被綠了垒探。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,629評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡怠李,死狀恐怖圾叼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情捺癞,我是刑警寧澤夷蚊,帶...
    沈念sama閱讀 34,295評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站髓介,受9級特大地震影響惕鼓,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜唐础,卻給世界環(huán)境...
    茶點故事閱讀 39,901評論 3 313
  • 文/蒙蒙 一箱歧、第九天 我趴在偏房一處隱蔽的房頂上張望矾飞。 院中可真熱鬧,春花似錦呀邢、人聲如沸洒沦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽申眼。三九已至,卻和暖如春蝉衣,著一層夾襖步出監(jiān)牢的瞬間括尸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,978評論 1 266
  • 我被黑心中介騙來泰國打工病毡, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留濒翻,地道東北人。 一個月前我還...
    沈念sama閱讀 46,333評論 2 360
  • 正文 我出身青樓剪验,卻偏偏與公主長得像肴焊,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子功戚,可洞房花燭夜當晚...
    茶點故事閱讀 43,499評論 2 348

推薦閱讀更多精彩內(nèi)容