繁體中文

開發者工具 · URL 編碼器和解碼器

百分比編碼的工作原理:從字元到 UTF-8 位元組到 %XX 序列

· 工作原理

url 編碼 utf-8 百分比編碼 開發人員

透過 UTF-8 編碼步驟對應到百分比編碼的十六進位序列的字元代碼
原始 ToolAcre 向量圖

百分比編碼不編碼字元;它對位元組進行編碼。這篇文章展示了一個字元如何變成 UTF-8 位元組,然後變成十六進位對,以及為什麼重音字母需要兩個 %XX 組,而表情符號需要四個。

為什麼 'é' 變成 %C3%A9 而不是 %E9 — 揭示底層位元組層的觀察結果

當初級開發人員在 URL 中看到 %C3%A9 時,百分比編碼會對位元組而不是字元進行操作。字元 é 不是一個位元組; UTF-8 將其編碼為兩個:C3 A9。 RFC 3986 中的百分比編碼規則很簡單:將每個位元組編碼為百分號後面跟著兩個十六進位數字。這種區別將解釋從神秘轉變為合乎邏輯。

了解百分比編碼需要了解 UTF-8。文字必須使用字元編碼轉換為位元組。 UTF-8 是 URL 和 Web 的標準。它將字元表示為可變長度位元組序列:ASCII 使用一個字節,重音字母使用兩個位元組,表情符號使用四個位元組。每個階段都是不同的:字元、Unicode 代碼點、UTF-8 位元組,然後是 %XX 對。在不理解位元的情況下跳到十六進制就沒有抓到重點。

RFC 3986 的百分比編碼規則 — 每個位元組一個 % 後面跟著兩個十六進位數字,首選大寫

RFC 3986 定義了一個規則:將每個位元組編碼為百分比後面跟著兩個大寫十六進位數字。不需要編碼的非保留字元是字母、數字、連字符、底線、句點和波形符。其他一切都必須編碼。空格變成 %20,斜線變成 %2F,百分號變成 %25。這可以防止查詢值中的特殊字元破壞 URL 結構。

空格編碼為位元組 0x20,成為 %20。正斜線是 0x2F,變成 %2F。這些是需要一個位元組的 ASCII 字元。重音字母和表情符號不同。百分號變成 %25。保留的分隔符號(如冒號)被編碼以保留結構。這可以防止查詢參數中嵌入的“&”或“等於”破壞解析。每個位元組變成%HH。

UTF-8 作為假定的字元集 — 為什麼現代 URL 是 UTF-8 以及遺留異常在哪裡

UTF-8 使用可變長度編碼。從代碼點 0 到 127 的 ASCII 是一個位元組。從 128 到 2047 的字元(包括重音的拉丁字母)是兩個位元組。東亞文字中常見的從 2048 到 65535 的字元為三個位元組。 65535 以上的字元(包括大多數表情符號)為四個位元組。每個位元組都以表示後面有多少位元組的位元作為前綴。

重音的字母 é 是 Unicode 代碼點 U+00E9。 UTF-8 將其編碼為兩個位元組:0xC3 和 0xA9。百分比編碼產生%C3%A9。德語 ü (U+00FC) 編碼為 0xC3 0xBC,變成 %C3%BC。西班牙文 ñ (U+00F1) 編碼為 0xC3 0xB1,變成 %C3%B1。此模式是一致的:第一個位元組表示一個兩位元組序列。在編碼中,一個帶有重音的字母會擴展六個字元。

工作範例:逐位元組編碼「café 😀」 — 代碼點、UTF-8 位元組和結果字串

Emoji 使位元組層變得明顯。豎起大拇指的表情符號👍是代碼點U+1F44D。 UTF-8 將其編碼為四個位元組:F0 9F 91 8D。百分比編碼產生 %F0%9F%918D:1 個符號對應 12 個字元。笑臉 😀 (U+1F600) 編碼為 F0 9F 98 80,變成 %F0%9F%9880。四位元組序列變成百分之十二編碼的字元。

混合文字說明了為什麼理解位元組很重要。短語“café 😀”包含純 ASCII、重音符號和表情符號。字母 c、a、f 編碼為 63、61、66。 é 編碼為 C3 A9。空格編碼為 20。表情符號編碼為 F0 9F 98 80。結果是「caf%C3%A9%20%F0%9F%9880」。了解哪些位元組需要編碼可以使輸出變得可預測。

反向解碼 — 將 %XX 群組收集到位元組中,然後將它們解釋為 UTF-8

解碼則反轉該過程。解碼器掃描 %XX 對並將它們收集為位元組值。看到%C3%A9,它提取位元組C3和A9。 UTF-8 解碼將它們解釋為字元 é。如果序列不完整,例如單獨的 %C3,則結果是錯誤。解碼器從 UTF-8 前綴位元得知 C3 需要第二個位元組。

十六進位數字中大小寫無關緊要; %C3%A9 和 %c3%a9 解碼相同。 RFC 允許使用大寫或小寫,但首選大寫。但字元的大小寫很重要:é(如 %C3%A9)與 É(如 %C3%89)不同。 URL 比較必須標準化百分比編碼,否則可能會將相同的資源視為不同的資源。框架在快取之前進行標準化。

為什麼大小寫在十六進位數字中並不重要,但在其他地方卻很重要 - 規範化規則和 URL 比較

RFC 3986 提到網域名稱的 punycode 和提交的表單編碼作為單獨的規則。 Punycode 對不含百分號的非 ASCII 網域進行編碼,以實現 DNS 相容性。網域名稱 😀.example 變成「xn--js8h.example」。表單編碼修改百分比編碼,但有一個例外:空格變成加號而不是 %20。以 application/x-www-form-urlencoded 提交的表格使用加號作為空格。

URL 編碼器工具顯示所有三種模式:元件編碼、整體 URL 編碼和表單編碼。使用encodeURIComponent進行元件編碼對每個特殊字元(包括分隔符號)進行編碼,適合查詢值。使用encodeURI 進行整個URL 編碼可保留完整URL 的結構字元。表單編碼適用於 POST 內文。每個都使用 UTF-8;它們的差異僅在於哪些位元組未編碼。

Punycode 和表單編碼:兄弟標準,而不是百分比編碼擴展

位元組視角解決了 URL 之謎。為什麼一個表情符號需要十二個字元?因為 UTF-8 使用四個位元組,每個位元組變成 %HH。為什麼有些 URL 帶有 %2F 斜杠,而其他 URL 則帶有普通斜杠?因為編碼模式決定:路徑段中的斜線保持未編碼,但在查詢值內它必須是 %2F 以避免誤讀。

以位元組為單位考慮可預測的百分比編碼。字元是一個 Unicode 代碼點。 UTF-8 是其位元組表示形式。百分比編碼是傳輸格式。字元擴充發生在 UTF-8 層。十六進位大小寫不影響解碼,但字元大小寫會影響。由於嚴格的前綴規則,無效位元組序列在 UTF-8 處失敗。 URL 編碼器工具顯示了這項進展。

重點:以位元組為單位思考 — URL 編碼器和解碼器如何在瀏覽器中為您貼上的任何文字顯示準確的 %XX 輸出

工作範例:編碼「café 😀」。單字咖啡館包含字母 c、a、f 作為 ASCII 單字節:63、61、66。 é 是 UTF-8 兩個位元組:C3 A9。空間為 20。表情符號😀有四個位元組:F0 9F 98 80。未保留的 ASCII 字母保持可見。結果:「caf%C3%A9%20%F0%9F%9880」。這說明了為什麼一個表情符號擴展到十二個字元。

重點:以位元組為單位思考,而不是字元。百分比編碼在 UTF-8 編碼之後套用。每個位元組變成%HH。可變長度 UTF-8 表示字元擴充不同:ASCII 變成 %XX(兩個字元),兩個位元組重音變成 %XX%XX(六個字元),四位元組表情符號變成 %XX%XX%XX%XX(十二個字元)。將文字貼到 URL 編碼器工具中並觀察進度。