為什么要進(jìn)行URI編解碼淳附、怎么做?

本文主要針對URI編解碼的相關(guān)問題做了介紹蠢古,對Url編碼中哪些字符需要編碼奴曙、為什么需要編碼做了詳細(xì)的說明,并對比分析了Javascript 中和編解碼相關(guān)的幾對函數(shù)escape / unescape,encodeURI / decodeURI和encodeURIComponent / decodeURIComponent

預(yù)備知識

image.png

URI是統(tǒng)一資源標(biāo)識的意思草讶,通常我們所說的Url只是URI的一種洽糟。典型Url的格式如上面所示。下面提到的Url編碼,實際上應(yīng)該指的是URI編碼坤溃。

為什么需要Url編碼

通常如果一樣?xùn)|西需要編碼拍霜,說明這樣?xùn)|西并不適合傳輸。原因多種多樣薪介,如Size過大祠饺,包含隱私數(shù)據(jù),對于Url來說汁政,之所以要進(jìn)行編碼道偷,是因為Url中有些字符會引起歧義。

例如Url參數(shù)字符串中使用key=value鍵值對這樣的形式來傳參记劈,鍵值對之間以&符號分隔勺鸦,如/s?q=abc& ie=utf-8。如果你的value字符串中包含了=或者&目木,那么勢必會造成接收Url的服務(wù)器解析錯誤换途,因此必須將引起歧義的&和= 符號進(jìn)行轉(zhuǎn)義,也就是對其進(jìn)行編碼嘶窄。

又如怀跛,Url的編碼格式采用的是ASCII碼距贷,而不是Unicode柄冲,這也就是說你不能在Url中包含任何非ASCII字符,例如中文忠蝗。否則如果客戶端瀏覽器和服務(wù)端瀏覽器支持的字符集不同的情況下现横,中文可能會造成問題。

Url編碼的原則就是使用安全的字符(沒有特殊用途或者特殊意義的可打印字符)去表示那些不安全的字符阁最。

哪些字符需要編碼

RFC3986文檔規(guī)定戒祠,Url中只允許包含英文字母(a-zA-Z)、數(shù)字(0-9)速种、-_.~4個特殊字符以及所有保留字符姜盈。

RFC3986文檔對Url的編解碼問題做出了詳細(xì)的建議,指出了哪些字符需要被編碼才不會引起Url語義的轉(zhuǎn)變配阵,以及對為什么這些字符需要編碼做出了相應(yīng)的解釋馏颂。

US-ASCII字符集中沒有對應(yīng)的可打印字符

Url中只允許使用可打印字符。US-ASCII碼中的10-7F字節(jié)全都表示控制字符棋傍,這些字符都不能直接出現(xiàn)在Url中救拉。同時,對于80-FF字節(jié)(ISO-8859-1)瘫拣,由于已經(jīng)超出了US-ACII定義的字節(jié)范圍亿絮,因此也不可以放在Url中。

保留字符

Url可以劃分成若干個組件,協(xié)議派昧、主機(jī)黔姜、路徑等。有一些字符(:/?#[]@)是用作分隔不同組件的斗锭。例如:冒號用于分隔協(xié)議和主機(jī)地淀,/用于分隔 主機(jī)和路徑,?用于分隔路徑和查詢參數(shù)岖是,等等帮毁。還有一些字符(!$&'()*+,;=)用于在每個組件中起到分隔作用的,如=用于表示查詢參數(shù)中 的鍵值對豺撑,&符號用于分隔查詢多個鍵值對烈疚。當(dāng)組件中的普通數(shù)據(jù)包含這些特殊字符時,需要對其進(jìn)行編碼聪轿。

!|* ' ( ) ; : @ & = + $ , / ? # [ ] **

不安全字符

還有一些字符爷肝,當(dāng)他們直接放在Url中的時候,可能會引起解析程序的歧義陆错。這些字符被視為不安全字符灯抛,原因有很多。

動詞 含義
空格 Url在傳輸?shù)倪^程音瓷,或者用戶在排版的過程对嚼,或者文本處理程序在處理Url的過程,都有可能引入無關(guān)緊要的空格绳慎,或者將那些有意義的空格給去掉
引號以及<> 引號和尖括號通常用于在普通文本中起到分隔Url的作用
# 通常用于表示書簽或者錨點
% 百分號本身用作對不安全字符進(jìn)行編碼時使用的特殊字符纵竖,因此本身需要編碼
{}\|^[]`~ 某一些網(wǎng)關(guān)或者傳輸代理會篡改這些字符

需要注意的是,對于Url中的合法字符杏愤,編碼和不編碼是等價的靡砌,但是對于上面提到的 這些字符,如果不經(jīng)過編碼珊楼,那么它們有可能會造成Url語義的不同通殃。因此對于Url而言,只有普通英文字符和數(shù)字厕宗,特殊字符$-_.+!*'()還有保留 字符画舌,才能出現(xiàn)在未經(jīng)編碼的Url之中。其他字符均需要經(jīng)過編碼之后才能出現(xiàn)在Url中媳瞪。

但是由于歷史原因骗炉,目前尚存在一些不標(biāo)準(zhǔn)的編碼實現(xiàn)。例如對于符號蛇受,雖然RFC3986文檔規(guī)定句葵,對于波浪符號,不需要進(jìn)行Url編碼,但是還是有很多老的網(wǎng)關(guān)或者傳輸代理會

Javascript中的escape,encodeURI和encodeURIComponent的區(qū)別

Javascript中提供了3對函數(shù)用來對Url編碼以得到合法的Url乍丈,它們分別是escape / unescape,encodeURI / decodeURI和encodeURIComponent / decodeURIComponent剂碴。由于解碼和編碼的過程是可逆的,因此這里只解釋編碼的過程轻专。

這三個編碼的函數(shù)——escape忆矛,encodeURI,encodeURIComponent——都是用于將不安全不合法的Url字符轉(zhuǎn)換為合法的Url字符表示请垛,它們有以下幾個不同點

安全字符不同

下面的表格列出了這三個函數(shù)的安全字符(即函數(shù)不會對這些字符進(jìn)行編碼)

安全字符
escape(69個) */@+-._0-9a-zA-Z
encodeURI(82個) !#$&'()*+,/:;=?@-._~0-9a-zA-Z
encodeURIComponent(71個) !'()*-._~0-9a-zA-Z

兼容性不同

escape函數(shù)是從Javascript1.0的時候就存在了催训,其他兩個函數(shù)是在Javascript1.5才引入的。但是由于 Javascript1.5已經(jīng)非常普及了宗收,所以實際上使用encodeURI和encodeURIComponent并不會有什么兼容性問題漫拭。

對Unicode字符的編碼方式不同

這三個函數(shù)對于ASCII字符的編碼方式相同,均是使用百分號+兩位十六進(jìn)制字符來表示混稽。但是對于Unicode字符采驻,escape的編碼方式是%uxxxx,其中的xxxx是用來表示unicode字符的4位十六進(jìn)制字符匈勋。這種方式已經(jīng)被W3C廢棄了礼旅。但是在ECMA-262標(biāo)準(zhǔn)中仍然保留著escape的這種編碼語法。encodeURI和encodeURIComponent則使用UTF-8對非ASCII字符進(jìn)行編碼洽洁,然后再進(jìn)行百分號編碼痘系。這是RFC推薦的。因此建議盡可能的使用這兩個函數(shù)替代escape進(jìn)行編碼诡挂。

適用場合不同

encodeURI被用作對一個完整的URI進(jìn)行編碼碎浇,而encodeURIComponent被用作對URI的一個組件進(jìn)行編碼临谱。

從上面提到的安全字符范圍表格來看璃俗,我們會發(fā)現(xiàn),encodeURIComponent編碼的字符范圍要比encodeURI的大悉默。我們上面提到 過城豁,保留字符一般是用來分隔URI組件(一個URI可以被切割成多個組件,參考預(yù)備知識一節(jié))或者子組件(如URI中查詢參數(shù)的分隔符)抄课,如:號用于分隔 scheme和主機(jī)唱星,?號用于分隔主機(jī)和路徑。由于encodeURI操縱的對象是一個完整的的URI跟磨,這些字符在URI中本來就有特殊用途间聊,因此這些保 留字符不會被encodeURI編碼,否則意義就變了抵拘。

組件內(nèi)部有自己的數(shù)據(jù)表示格式哎榴,但是這些數(shù)據(jù)內(nèi)部不能包含有分隔組件的保留字符,否則就會導(dǎo)致整個URI中組件的分隔混亂。因此對于單個組件使用encodeURIComponent尚蝌,需要編碼的字符就更多了迎变。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市飘言,隨后出現(xiàn)的幾起案子衣形,更是在濱河造成了極大的恐慌,老刑警劉巖姿鸿,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谆吴,死亡現(xiàn)場離奇詭異,居然都是意外死亡苛预,警方通過查閱死者的電腦和手機(jī)纪铺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來碟渺,“玉大人鲜锚,你說我怎么就攤上這事∩慌模” “怎么了芜繁?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長绒极。 經(jīng)常有香客問我骏令,道長,這世上最難降的妖魔是什么垄提? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任榔袋,我火速辦了婚禮,結(jié)果婚禮上铡俐,老公的妹妹穿的比我還像新娘凰兑。我一直安慰自己,他們只是感情好审丘,可當(dāng)我...
    茶點故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布吏够。 她就那樣靜靜地躺著,像睡著了一般滩报。 火紅的嫁衣襯著肌膚如雪锅知。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天脓钾,我揣著相機(jī)與錄音售睹,去河邊找鬼。 笑死可训,一個胖子當(dāng)著我的面吹牛昌妹,可吹牛的內(nèi)容都是我干的生真。 我是一名探鬼主播,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼捺宗,長吁一口氣:“原來是場噩夢啊……” “哼柱蟀!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蚜厉,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤长已,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后昼牛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體术瓮,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年贰健,在試婚紗的時候發(fā)現(xiàn)自己被綠了胞四。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,427評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡伶椿,死狀恐怖辜伟,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情脊另,我是刑警寧澤导狡,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站偎痛,受9級特大地震影響旱捧,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜踩麦,卻給世界環(huán)境...
    茶點故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一枚赡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧谓谦,春花似錦贫橙、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽谓松。三九已至星压,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鬼譬,已是汗流浹背娜膘。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留优质,地道東北人竣贪。 一個月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓军洼,卻偏偏與公主長得像,于是被迫代替她去往敵國和親演怎。 傳聞我的和親對象是個殘疾皇子匕争,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,440評論 2 359

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