繁體中文

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

Plus 與 %20:應用程式的歷史/x-www-form-urlencoded

· 背景

url 編碼 html 表單 http 標准

表單提交顯示查詢字串中的加號編碼空間與 URI 語法中的百分之二十
原始 ToolAcre 向量圖

表單將空格編碼為 +,而 URI 標準表示為 %20,這是歷史原因。這篇文章追溯了從早期 HTML 表單到今天的 WHATWG 定義的約定,並解釋了為什麼它從未消失。

Plus 與 %20 — 為什麼表單和 URI 對空格進行不同的編碼

以 GET 提交的 HTML 表單將空格編碼為查詢字串中的加號。在遵循 RFC 3986 的 URL 中,相同的空格將變成 %20。兩者都是正確的,因為它們遵循不同的標準。包含空格的表單欄位在表單編碼中變成 name=value+with+spaces,但在 RFC 3986 中變成 %20。加百分之二十的差異標誌著哪個標準適用於您的資料。

表單編碼使用加號作為空格,作為 RFC 1866 (1995)、HTML 2.0 的原始表單提交定義的歷史約定。 GET 請求將空格編碼為加號,將加號保留為文字 + 編碼為 %2B。此規則僅適用於 application/x-www-form-urlencoded, 而非一般 URI 語法。數十億個伺服器框架開始依賴這項約定。兩者的測試顯示出明顯的差異:表單模式產生加號; URI 模式產生 %20。 URL編碼器和解碼器提供兩種模式可以直接比較。

早期的 HTML 表單和 GET 提交 - 表單編碼是如何定義的以及為什麼選擇 +

RFC 1866 (1995) 定義的表單提交,其中空格變成加號,文字加號變為 %2B。這只適用於 application/x-www-form-urlencoded. RFC 3986 為一般 URI 語法指定 %20。兩種標準故意並存。

RFC 2396 比早期標準更嚴格地闡明了字元集。它將服務於 URI 結構的保留字元與作為文字資料的非保留字元形式化。標準機構隨著瀏覽器和代理行為的發展而將其標準化。 RFC 3986 後來出現,沒有改變編碼行為,只是澄清了符號。目前所有瀏覽器都標準化 UTF-8 編碼。 HTML 表單透過提交按鈕傳送 application/x-www-form-urlencoded 格式,並以加號表示空格。手動 URI 構造使用 %20。了解這兩個標準可以防止整合出現意外。

RFC 1866 和後來的 HTML 規格 — 規則的編寫位置以及它與 URI 語法的差異

WHATWG URL 標準指定 URLSearchParams.toString() 產生具有空格加號的 application/x-www-form-urlencoded 輸出。 URL 建構函式依照 RFC 3986 進行百分比編碼。瀏覽器導航到帶有空格編碼的 URL %20;作為 GET 提交的表單編碼為 plus。這些根本不同的工具有不同的用途。手動encodeURIComponent為空格提供%20 - RFC 3986樣式。提交到相同 URL 的表單會發送加號。解析表單提交的伺服器需要加上;接收 %20 會導致靜默參數失敗。

對兩者進行測試揭示了您所依賴的伺服器端假設。 JavaScript URLSearchParams 提供安全的表單樣式編碼隱藏和複雜性。建構 URLSearchParams,附加條目,呼叫 toString() 以使用適當的加號來取得 application/x-www-form-urlencoded 。或使用encodeURIComponent建立查詢字串;您會收到 RFC 3986 %20。切勿混合使用方法。手動加上和encodeURIComponent 的查詢字串會產生歧義。接收者無法區分加號是表示空格還是字面上的加號。標準方法處理一致。

現今的 URL 標準 — application/x-www-form-urlencoded 作為具有自己規則的單獨序列化程序

JSON API 通常拒絕加號作為空格,根據 RFC 3986 期望 %20。客戶端發送 plus 會默默失敗:參數消失。使用兩種編碼測試 API 可以揭示它們接受哪種標準。 JavaScript 中的 URLSearchParams 處理表單編碼。 URL 編碼器和解碼器產生 RFC 3986 %20。

HTML 表單提交會自動處理編碼。您的伺服器框架決定要應用哪些規則。 Rails、Django、PHP 都會自動將接收到的表單資料中的加號視為空格。但為相同端點手動建立查詢字串非常重要。上傳的加號會產生歧義。規範合規性和實際伺服器行為略有不同。記錄您的端點期望的標準。測試兩種編碼風格。防禦性程式碼可以很好地處理這兩個問題。

工作範例:將相同表單欄位視為查詢字串和請求正文 — 在一個地方使用 +,在另一個地方使用 %20

JavaScript URLSearchParams 應用程式表單編碼:空格變成加號,而不是 %20。 new URLSearchParams({q: "hello world"}) 產生“q=hello+world”,而不是“q=hello%20world”。這是專門內建在 JavaScript 中的歷史 application/x-www-form-urlencoded 規則。但是將此字串作為原始查詢傳遞給新 URL 會使加號保持為加號;只有 URLSearchParams 將其解碼為空格。構造函數忠於它所看到的。當錯誤地混合函數時,加號差異會導致常見錯誤。

URL 建構子和encodeURIComponent 是不同的工具。 encodeURIComponent 對除了未保留的字母、數字和 - _ 之外的幾乎所有內容進行編碼。 ! 〜*'()。它假設沒有上下文。 URL 建構子解析實際 URL 並套用每個元件的 WHATWG 規則。 encodeURIComponent 將「hello/world"」轉換為「hello%2Fworld」;新 URL 將斜線視為路徑分隔符號。相同的輸入,不同的輸出。透過連接片段建立 URL 時使用encodeURIComponent。使用 URLSearchParams 或 URL 建構子來取得完整或部分 URL。

為什麼它無法修復 - 數十年的伺服器和客戶端依賴當前的行為

百分比編碼規則從 RFC 1738 (1994) 發展到 RFC 2396 (1998) 到 RFC 3986 (2005)。每一代人都澄清了含糊之處。 RFC 1738 是保守的,對待字元不安全,因為早期的網路對字元的支援有限。部署在 UTF-8 上標準化,實作變得一致。後來的標準放寬了對跨系統證明安全的字元的限制。現代共識:UTF-8 無所不在。標準機構大力維護向後相容性。修復問題需要全球範圍內的協調——三十年後這是不可能的。兩種標準有意共存。

使用 plus 和 %20 進行測試揭示了伺服器假設。伺服器日誌顯示客戶端發送的內容。表格使用加號;手動 URL 使用 %20。根據上下文進行選擇並遵循 API 檔案。

這不包括 - multipart/form-data 和 JSON 主體

測試這兩種編碼可以揭示伺服器行為。雙向發送 a+b。許多生產伺服器都需要表單編碼;較新的 API 預計為 %20。您的選擇取決於接收者的期望。 URLSearchParams 處理表單編碼; encodeURIComponent 處理 RFC 編碼。

切勿組合編碼方法。使用encodeURIComponent %2B 編碼然後傳遞給URLSearchParams 的值將被雙重編碼為%252B。解碼一次會產生 %2B 而不是加號。字元變成文字百分二六字串而不是加號。檢查建置過程中的中間步驟。每個值只發生一次編碼。記錄您的管道使用哪種編碼標準。使用特殊字元進行測試,包括加號、空格、& 符號。

重點:兩個標準,在各自的上下文中都是正確的 - URL 編碼器和解碼器如何為您提供 RFC 3986 形式,其中 %20 表示空格,這樣您就知道您正在查看哪一個

加對二十的分裂並不是一個需要修復的錯誤。它是以不同方式解決不同問題的標準的歷史產物。修復問題需要全球範圍內的協調——三十年後這是不可能的。標準機構不會追溯性地破壞網路。 RFC 3986、表單規則、瀏覽器URL構造各有標準與理由。 RFC 1866 表單編碼和 RFC 3986 URI 編碼服務於不同的層。故意編碼以了解您的標準。針對實際有效負載進行測試。

根據上下文選擇編碼。表單根據 HTML 標準使用 plus。根據 RFC 3986,手動 URI 使用 %20。 API 指定了期望的內容;遵循檔案或測試兩者。 URL 編碼器和解碼器顯示 RFC 3986。需要表單編碼嗎? URLSearchParams 就是這樣做的。工具不混合編碼;了解標准可以防止出現意外。層之間的編碼不一致會導致细微的参數丢失、截斷、資料损坏。這兩個標準在各自的領域都是正確的。謹慎申請並記錄。