percent-encode 百分號編碼


原文地址:http://www.imkevinyang.com/2009/08/詳解javascript中的url編解碼.html

 

摘要

  • URI(統一資源標識)編解碼
  • 為什么需要編碼 
  • 哪些需要編碼
  • 如何編碼

 

預備知識

   foo://example.com:8042/over/there?name=ferret#nose  
   \_/  \______________/ \________/\_________/ \__/  
    |          |              |         |        |  
 scheme    authority        path      query   fragment

  上面為典型的URL的格式。由於URL屬於URI的一種,所以下面提到的URL編碼,實際上應該指的是URI編碼。

 

為什么需要URL編碼?

  通常如果一樣東西需要編碼,說明這樣東西並不適合傳輸。原因多種多樣,如:內容Size過大、包含隱私數據等。

  URL的編碼原因是因為URL中有些字符會引起歧義例如:URL參數字符串中使用鍵值對(key=value)的方式來傳參,鍵值對之間以&符號分隔,如"/s?q=abc& ie=utf-8"。如果value字符串中包含了'='或者'&',那么勢必會造成接收URL的服務器解析錯誤,因此必須將引起歧義的'='或者'&'符號進行轉義,也就是對其進行編碼。

  又如,URL的編碼格式采用的是ASCII碼,而不是Unicode,所以你不能在URL中包含任何非ASCII字符,例如中文。否則如果客戶端瀏覽器和服務端瀏覽器支持的字符集不同的情況下,可能會造成問題。

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

 

哪些字符需要編碼?

RFC3986文檔規定,URL中只允許包含英文字母(a-zA-Z)、數字(0-9)4個特殊字符(- _ . ~)以及所有保留字符。

  RFC3986文檔對URL的編解碼問題做出了詳細的建議,指出了哪些字符需要被編碼才不會引起URL語義的轉變,以及對為什么這些字符需要編碼做出了相應的解釋。

  URL只允許使用可打印字符US-ASCII碼中的10-7F字節全都表示控制字符,這些字符都不能直接出現在URL中。同時,對於80-FF字節(ISO-8859-1),由於已經超出了US-ACII定義的字節范圍,因此也不可以放在URL中。

  保留字符URL可以划分成若干個組件協議、主機、路徑等。有一些字符(:/?#[]@)是用作分隔不同組件的。例如':'用於分隔協議和主機,'/'用於分隔主機和路徑,'?'用於分隔路徑和查詢參數,等等。還有一些字符(!$&'()*+,;=)用於在每個組件中起到分隔作用的,如'='用於表示查詢參數中 的鍵值對,'&'符號用於分隔查詢多個鍵值對。當組件中的普通數據包含這些特殊字符時,需要對其進行編碼。RFC3986中指定了以下字符為保留字符:

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

 

  不安全字符。還有一些字符,當他們直接放在URL中的時候,可能會引起解析程序的歧義。這些字符被視為不安全字符,原因有很多。

空格
在傳輸、用戶排版、文本處理程序處理URL的過程中都有可能引入無關緊要的空格或者去掉了有意義的空格
引號以及<> 引號和尖括號通常用於在普通文本中起到分隔Url的作用
# 通常用於表示書簽或者錨點
% 百分號本身用作對不安全字符進行編碼時使用的特殊字符,因此本身需要編碼
{}|\^[]`~ 某一些網關或者傳輸代理會篡改這些字符

 

  注意:對於URL中的合法字符,編碼和不編碼是等價的,但對於上面提到的這些字符如果不經過編碼,那么它們有可能會造成URL語義的不同。因此對於URL而言,只有普通英文字符和數字,特殊字符$-_.+!*'()還有保留字符,才能出現在未經編碼的URL之中。其他字符均需要經過編碼。

  但是由於歷史原因,目前尚存在一些不標准的編碼實現。例如對於'~'符號,雖然RFC3986文檔規定,對於波浪符號~,不需要進行URL編碼,但是還是有很多老的網關或者傳輸代理會。

 

如何對Url中的非法字符進行編碼?

  URL編碼通常也被稱為百分號編碼(Url Encoding,also known as percent-encoding),是因為它的編碼方式非常簡單,使用%百分號加上兩位的字符(十六進制0~F)URL編碼默認使用的字符集是US-ASCII。例如 a US-ASCII碼中對應的字節是0x61,那么URL編碼之后得到的就 是%61,我們在地址欄上輸入http://g.cn/search?q=%61%62%63,實際上就等同於在google上搜索abc了。又如@符號在ASCII字符集中對應的字節為0x40,經過URL編碼之后得到的是%40

  常見字符的URL編碼列表:

保留字符的URL編碼
! * " ' ( ) ; : @ &
%21 %2A %22 %27 %28 %29 %3B %3A %40 %26
= + $ , / ? % # [ ]
%3D %2B %24 %2C %2F %3F %25 %23 %5B %5D

 

  對於非ASCII字符,需要使用ASCII字符集的超集進行編碼得到相應的字節,然后對每個字節執行百分號編碼。 對於Unicode字符,RFC文檔建議使用utf-8對其進行編碼得到相應的字節,然后對每個字節執行百分號編碼。如"中文"使用UTF-8字符集得到的字節為0xE4 0xB8 0xAD 0xE6 0x96 0x87,經過URL編碼之后得到"%E4%B8%AD%E6%96%87"。

  如果某個字節對應着ASCII字符集中的某個非保留字符,則此字節無需使用百分號表示。 例如"URL編碼",使用UTF-8編碼得到的字節是0x55 0x72 0x6C 0xE7 0xBC 0x96 0xE7 0xA0 0x81,由於前三個字節對應着ASCII中的非保留字符"URL",因此這三個字節可以用非保留字符"URL"表示。最終的URL編碼可以簡化成"URL%E7%BC%96%E7%A0%81",當然,如果你用"%55%72%6C%E7%BC%96%E7%A0%81"也是可以的。

  由於歷史的原因,有一些URL編碼實現並不完全遵循這樣的原則。

 

其他和URL編碼相關的問題

  對包含中文的URL的處理問題,不同瀏覽器有不同的表現。例如對於IE,如果你勾選了高級設置"總是以UTF-8發送URL",那么URL路徑部分的中文會使用UTF-8進行URL編碼之后發送給服務端,而查詢參數中的中文部分使用系統默認字符集進行URL編碼。為了保證最大的互操作性,建議所有放到URL中的組件全部顯式指定某個字符集進行URL編碼,而不依賴於瀏覽器的默認實現。

  另外,很多HTTP監視工具或者瀏覽器地址欄等在顯示URL的時候會自動將URL進行一次解碼(使用UTF-8字符集),這就是為什么當你在 Firefox中訪問Google搜索中文的時候,地址欄顯示的URL包含中文的緣故。但實際上發送給服務端的原始URL還是經過編碼的。你可以在地址欄上使用Javascript訪問location.href就可以看出來了。在研究URL編解碼的時候千萬別被這些假象給迷惑了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM