百分號編碼

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

## URI的百分號編碼

### URI的字符類型

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

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

`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年發布的規定， URI中的二進位數據應該表示為8位元組的序列，然後對每個8位元組按照上述方式百分號編碼. 例如，字節值0F（十六進位）應表示為"`%0F`"，字節值41（十六進位）應表示為"`A`"或"`%41`". 優先使用未保留字符來表示這些字節值，因為這使得URL更短。

#### 字符數據

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

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

### 當前標準

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

### 非標準的實現

有一些不符合標準的把Unicode字符在URI中表示為：`%u''xxxx''`, 其中xxxx是用4個十六進位數字表示的Unicode的碼位值。任何RFC都沒有這樣的字符表示方法，並且已經被W3C 拒絕。第三版的ECMA-262仍然包含函數`escape(<var>string</var>)`使用這種語法，但也有函數`encodeURI(<var>uri</var>)`轉換字符到UTF-8位元組序列並用百分號編碼每個字節。

## application/x-www-form-urlencoded類型

當HTML表單中的數據被提交時，表單的域名與值被編碼並通過HTTP的GET或者POST方法甚至更古遠的email把請求發送給伺服器。這裡的編碼方法採用了一個非常早期的通用的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頭內部。

## 外部連結

- RFC 3986 / STD 66 (plus errata ), the current generic URI syntax specification.
- RFC 2396 (obsolete, plus errata ) and RFC 2732 (plus errata ) together comprised the previous version of the generic URI syntax specification.
- RFC 1738 (mostly obsolete) and RFC 1808 (obsolete), which define URLs.
- RFC 1630 (obsolete), the first generic URI syntax specification.
- W3C Guidelines on Naming and Addressing: URIs, URLs, ...
- W3C explanation of UTF-8 in URIs
- W3C HTML form content types
- 線上URL編解碼工具