HTTP 冷知識 | HTTP 請求中,空格應該被編碼爲 %20 仍是 + ?

HTTP 請求中,空格應該被編碼爲何?今天咱們走進 RFC 文檔W3C 文檔,瞭解一下這個「史詩級」大坑。javascript

1.%20 仍是 +

開始講解前先看個小測試,在瀏覽器裏輸入 blank testblanktest 間有個空格),咱們看看瀏覽器如何處理的:html

從動圖能夠看出瀏覽器把空格解析爲一個加號「+」。前端

是否是感受有些奇怪?咱們再作個測試,用瀏覽器提供的幾個函數試一下:java

encodeURIComponent("blank test") // "blank%20test"
encodeURI("q=blank test")        // "q=blank%20test"
new URLSearchParams("q=blank test").toString() // "q=blank+test"
複製代碼

image-20200524184735653

代碼是不會說謊的,其實上面的結果都是正確的,encode 結果不同,是由於 URI 規範W3C 規範衝突了,纔會搞出這種讓人疑惑的烏龍事件。node

2.衝突的協議

咱們首先看看 URI 中的保留字,這些保留字不參與編碼。保留字符一共有兩大類:webpack

  • gen-delims:: / ? # [ ] @
  • sub-delims:! $ & ' ( ) * + , ; =

URI 的編碼規則也很簡單,先把非限定範圍的字符轉爲 16 進制,而後前面加百分號。git

空格這種不安全字符轉爲十六進制就是 0x20,前面再加上百分號 % 就是 %20github

image-20200524184601512

因此這時候再看 encodeURIComponentencodeURI 的編碼結果,就是徹底正確的。web

既然空格轉爲%20 是正確的,那轉爲 + 是怎麼回事?這時候咱們就要了解一下 HTML form 表單的歷史。promise

早期的網頁沒有 AJAX 的時候,提交數據都是經過 HTML 的 form 表單。form 表單的提交方法能夠用 GET 也能夠用 POST,你們能夠在 MDN form 詞條上測試:

通過測試咱們能夠看出表單提交的內容中,空格都是轉爲加號的,這種編碼類型就是 application/x-www-form-urlencoded,在 WHATWG 規範裏是這樣定義的:

image-20200524185912590

到這裏基本上就破案了,URLSearchParams 作 encode 的時候,就按這個規範來的。我找到了 URLSearchParamsPolyfill 代碼,裏面就作了 %20+ 的映射:

replace = {
    '!': '%21',
    "'": '%27',
    '(': '%28',
    ')': '%29',
    '~': '%7E',
    '%20': '+', // <= 就是這個
    '%00': '\x00'
}
複製代碼

規範裏對這個編碼類型還有解釋說明:

The application/x-www-form-urlencoded format is in many ways an aberrant monstrosity, the result of many years of implementation accidents and compromises leading to a set of requirements necessary for interoperability, but in no way representing good design practices. In particular, readers are cautioned to pay close attention to the twisted details involving repeated (and in some cases nested) conversions between character encodings and byte sequences. Unfortunately the format is in widespread use due to the prevalence of HTML forms.

這種編碼方式就不是個好的設計,不幸的是隨着 HTML form 表單的普及,這種格式已經推廣開了

其實上面一大段句話就是一個意思:這玩意兒設計的就是 💩,但積重難返,你們仍是忍一下吧

3.一句話總結

  • URI 規範裏,空格 encode 爲 %20application/x-www-form-urlencoded 格式裏,空格 encode 爲 +

  • 實際業務開發時,最好使用業內成熟的 HTTP 請求庫封裝請求,這些雜活兒累活兒框架都幹了;

  • 若是非要使用原生 AJAX 提交 application/x-www-form-urlencoded 格式的數據,不要手動拼接參數,要用 URLSearchParams 處理數據,這樣能夠避免各類噁心的編碼衝突。

5.感謝

本文到這裏就結束了,喜歡的話必定要點贊👍哦,謝謝你,這對我真的很重要

6.文章推薦

本文選自個人長文HTTP 規範中的那些暗坑,想要了解更多可點擊原文查看。

更多推薦:




最後推薦一下個人我的公衆號:「滷蛋實驗室」,平時會分享一些前端技術和數據分析的內容,你們感興趣的話能夠關注一波:


相關文章
相關標籤/搜索