百分號編碼

统一资源定位符的编码机制

百分號編碼(英語:Percent-encoding),又稱URL編碼URL encoding)是特定上下文的統一資源定位符(URL)的編碼機制,實際上也適用於統一資源標誌符(URI)的編碼。也用於為application/x-www-form-urlencoded MIME準備數據,因為它用於通過HTTP的請求操作(request)提交HTML表單數據。

URI的百分號編碼

URI的字符類型

URI所允許的字符分作保留未保留保留字符是那些具有特殊含義的字符,例如:斜線字符用於URL(或URI)不同部分的分界符;未保留字符沒有這些特殊含義。百分號編碼把保留字符表示為特殊字符序列。上述情形隨URI與URI的不同版本規格會有輕微的變化。

RFC 3986 section 2.2 保留字符 (2005年1月)
! * ' ( ) ; : @ & = + $ , / ? # [ ]
RFC 3986 section 2.3 未保留字符 (2005年1月)
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
a b c d e f g h i j k l m n o p q r s t u v w x y z
0 1 2 3 4 5 6 7 8 9 - _ . ~

URI中的其它字符必須用百分號編碼。

對保留字符的百分號編碼

如果一個保留字符在特定上下文中具有特殊含義(稱作「reserved purpose」) , 且URI中必須使用該字符用於其它目的,那麼該字符必須百分號編碼。百分號編碼一個保留字符,首先需要把該字符的ASCII的值表示為兩個16進制的數字,然後在其前面放置轉義字符(「%」),置入URI中的相應位置。(對於非ASCII字符,需要轉換為UTF-8字節序,然後每個字節按照上述方式表示。)

例如,"/",如果用作URI的路徑成份的分界符,則是具有特殊含義的保留字符。如果該字符需要出現在URI一個路徑成分的內部,則三字符序列"%2F"或"%2f"就用於代替原本的"/"出現在該URI路徑成分的內部.

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

在特定上下文中沒有特殊含義的保留字符也可以被百分號編碼,在語義上與不百分號編碼的該字符沒有差別。

在URI的"查詢"成分(?字符後的部分)中, 例如"/"仍然是保留字符但是沒有特殊含義,除非一個特定的URI有其它規定。該/字符在沒有特殊含義時不需要百分號編碼。

如果保留字符具有特殊含義,那麼該保留字符用百分號編碼的URI與該保留字符僅用其自身表示的URI具有不同的語義。

對未保留字符的百分號編碼

未保留字符不需要百分號編碼。

兩個URI的差別如果僅在於未保留字符是用百分號編碼還是用字符自身表示,那麼這兩個URI具有等價的語義。但URI處理器實際上並不總是把二者視作等價[來源請求]。例如,URI的消費者不應該把"%41"與"A","%7E"與"~"視作不同,但是某些URI的消費者就是這麼做了。為了最大的互操作性,URI的製造者不應該對未保留字符進行百分號編碼。

對百分號字符的百分號編碼

由於百分號字符("%")表示百分號編碼字節流的存在,因此百分號字符應該被編碼為3個字節的序列:"%25",用於URI內部。

對任意數據的百分號編碼

大多數URI涉及表示任意數據,例如IP地址文件系統路徑作為URI的成分。

二進數據

1994年發布的RFC 1738規定[1], URI中的二進制數據應該表示為8位元組的序列,然後對每個8位元組按照上述方式百分號編碼. 例如,字節值0F(十六進制)應表示為"%0F",字節值41(十六進制)應表示為"A"或"%41". 優先使用未保留字符來表示這些字節值,因為這使得URL更短。

字符數據

二進數據的百分號編碼過程已經被外推到字符數據,甚至到不適合或未被完全規範的地步。在WWW初創階段,僅僅處理ASCII字符是否編碼問題,還沒有什麼問題。但隨後發展到對非ASCII字符如何在URI中編碼,缺少標準規範的情況下導致了歧義性的解釋URI的錯誤。

例如, 基於RFC 1738與RFC 2396的協議規定,字符數據先要根據某種字符編碼轉換為字節流,然後再表示為URI。如果URI不提供是何種字符編碼的提示信息,那麼這個URI難以可靠的解析。

當前標準

2005年1月發布的RFC 3986,建議所有新的URI必須對未保留字符不加以百分號編碼;其它字符建議先轉換為UTF-8字節序列, 然後對其字節值使用百分號編碼。此前的URI不受此標準的影響。

非標準的實現

有一些不符合標準的把Unicode字符在URI中表示為:%uxxxx, 其中xxxx是用4個十六進制數字表示的Unicode的碼位值。任何RFC都沒有這樣的字符表示方法,並且已經被W3C拒絕頁面存檔備份,存於網際網路檔案館)。第三版的ECMA-262仍然包含函數escape(string)使用這種語法,但也有函數encodeURI(uri)轉換字符到UTF-8字節序列並用百分號編碼每個字節。

application/x-www-form-urlencoded類型

當HTML表單中的數據被提交時,表單的域名與值被編碼並通過HTTP的GET或者POST方法甚至更古遠的email[2]把請求發送給服務器。這裡的編碼方法採用了一個非常早期的通用的URI百分號編碼方法,並且有很多小的修改如換行規範化以及把空格符的編碼"%20"替換為"+" 。按這套方法編碼的數據的MIME類型是application/x-www-form-urlencoded,當前仍用於(雖然非常過時了)HTML與XForms規範中。此外,CGI規範包括了web服務器如何解碼這類數據、利用這類數據的內容。

如果發送的是HTTP GET請求,application/x-www-form-urlencoded數據包含在所請求URI的查詢成分中。如果發送的是HTTP POST請求或通過email,數據被放置在消息體中,媒體類型的名字被包含在消息的Content-Type頭內部。

參見

參考文獻

  1. ^ RFC 1738 §2.2; RFC 2396 §2.4; RFC 3986 §1.2.1, 2.1, 2.5
  2. ^ User-agent support for email based HTML form submission, using a 'mailto' URL as the form action, was proposed in RFC 1867 section 5.6, during the HTML 3.2 era. Various web browsers implemented it by invoking a separate email program or using their own rudimentary SMTP capabilities. Although sometimes unreliable, it was briefly popular as a simple way to transmit form data without involving a web server or CGI scripts.

外部連結