Zi 字媒體
2017-07-25T20:27:27+00:00
惱人的 URL Encode/Decode
我們常在開發 Web 時,會發生連結失效 (404 Page not found.)、特別的參數值傳遞不正確、Query String 解譯錯誤等等問題或 Bug。追究之後常常都是忽略了 URL 編碼或者用了不正確的編碼所造成,看來我們需要多多認識 URL 的特性,順便養成「對 URL 敏感」的習慣。
URI 規範的歷史淵源
先來看看 URI 的歷史。最早在 1994 年 12 月,RFC 1738 起頭定義了 URI 最初的規範。經過了幾年的混亂與磨練,一直到了 1998 年 8 月才有了比較廣泛的標準,那就是 RFC 2396。而我們最常接觸的 RFC 2616 (也就是 HTTP 1.1) 在處理 URI 也是遵循 RFC 2396 標準,我們可以在規範看見以下描述:
3.2.3 URI Comparison Characters other than those in the "reserved" and "unsafe" sets (see RFC 2396 [42]) are equivalent to their ""%" HEX HEX" encoding.
但是後來隨著環境的演進,直到 2005 年 1 月所發佈的 RFC 3986 最終成為目前主流所實作的規範。因此以目前來說,採用 RFC 3986 是比較明智的選擇。
PHP urlencode() 與 rawurlencode() 的差異
先來測試一下:
1
2
3
4
5
6
7
8
9
<?php
$str='1+2&b and c';
echo urlencode($str);
// show: 1+2&b+and+c
echo rawurlencode($str);
// show: 1+2&b and c
發現了嗎?兩者在於對空白 (space) 的處理有不同的邏輯,根據官方文件描述 PHP 中的 urlencode() function 是遵循 application/x-www-form-urlencoded (就是我們常說的 Query String) 編碼規範,因此會把 space 空白變成 + 而不是 ,如下:
urlencode differs from RFC 1738 by encoding spaces as + instead of
然而 PHP 中的 rawurlencode() function 是遵循 RFC 3986 進行實作,如下:
Encodes the given string according to » RFC 3986.
由此看來使用 rawurlencode() 才是最推薦的方法,測試如下:
JavaScript 中的 encodeURIComponent() 與 encodeURI() 的差異
JavaScript 測試如下:
1
2
3
4
5
6
7
8
9
<script type="text/javascript">
document.write(encodeURIComponent('1+2&b and c'));
// show: 1+2&b and c
</script>
<script type="text/javascript">
document.write(encodeURI('1+2&b and c'));
// show: 1+2&b and c
</script>
在 JavaScript 中,encodeURIComponent() 與 encodeURI() 差別在保留字 (不進行編碼的字元) 的定義不同:
encodeURI() 的保留字為 ~!@#$&*()=:/,;?+'
encodeURIComponent() 的保留字為 ~!*()'
此外 JavaScript 中的 encodeURIComponent() 也是遵循 RFC 3986 編碼,因此比較推薦採用這個函式。
討論
其實最混亂的就是 + 與 的問題,在 JavaScript 中所提供的 encodeURI() 並不是遵循 application/x-www-form-urlencoded 編碼規範,如果要在 JavaScript 環境下自行實作 application/x-www-form-urlencoded 編碼就必須先使用 encodeURIComponent() 轉換,然後再另外將 取代為 + 即可,如此就達到跟 PHP urlencode() 一樣的效果。
此外,我們在 Web 開發的過程中輸出 HTML 連結,雖然大多數瀏覽器都會很友善的自動對網址進行轉換再送出 HTTP Request 連線,但未了避免例外情況,我們還是遵循 RFC 3986 來處理 URL 比較正確,相容性也比較高。
參考資料
統一資源標誌符 URI Wiki
RFC 1738
RFC 2396
RFC 3986
PHP: rawurlencode - Manual
PHP: urlencode - Manual
分享到 Twitter(在新視窗中開啟)
按一下以分享至 Facebook(在新視窗中開啟)
分享到 LinkedIn(在新視窗中開啟)
點這裡寄給朋友(在新視窗中開啟)
按一下即可分享至 Skype(在新視窗中開啟)
分享到 Reddit(在新視窗中開啟)
分享到 Tumblr(在新視窗中開啟)
按一下以分享到 Telegram(在新視窗中開啟)
寫了
5860316篇文章,獲得
23313次喜歡