olNGIb4NkK5r2x7x4oG3GpEzizVpnY6KNCck9cym

淺談短網址(shorten-url)服務的編碼方式選擇

你有想過怎樣的編碼方式比較適合用於短網址服務(shorten-url)嗎?

在編碼方式如 Base64、Base32 中,所謂的填充(padding)是什麼意思? 一文中,筆者說明並舉例了在編碼方式中所謂的填充(padding)是什麼意思;那麼究竟什麼時候需要考慮到編碼方式是否因填充字元帶來影響呢?

編碼使用場景

一個十分常見的場景是當 編碼後的字串需要作為 URL 中的一部分 時,在 RFC 3986 規範中定義了統一資源標識符(Uniform Resource Identifier, URI)的通用格式,以確保兼容性與安全性:

  • 字元 :/?#[]@!&'()*+,;= 作為保留字元(reserved characters),具有特殊用途,不得隨意使用,否則會影響解析。
  • 字元 A-Za-z0-9-._~ 為非保留字元,可以安全出現在 URI 中,不需要額外編碼。
  • 對於中文、空白等特殊字元,需要轉換為百分號編碼(Percent-Encoding)。

因此 Base64 編碼並不能用做 URL 而需要採 URL-Safe Base64 編碼才行。

URL-Safe Base64 編碼是 Base64 編碼的變體,設計用來避免 URL 內的特殊字元衝突;會將 + 替換為 -/ 替換為 _ 並看需求決定是否要移除填充字元 =

適合短網址的編碼方式

在系統設計(system design)面試中,短網址服務幾乎可以說是常客中的常客了,但在這裡我們暫且不討論系統負載、資料庫選擇以及 API 設計,僅僅承接前面的話題:編碼(Encoding)

你有想過怎麼樣的編碼適合用於短網址服務嗎?選擇適當的編碼方式,會影響到編碼後的 辨識性安全性壓縮率

  • Base58 移除了易混淆字元,提高了辨識性,並且不存在特殊字元或 URI 保留字元,不需要額外轉換,不保證唯一性。
  • Base62 保留使用數字和大小寫字母,但避免 +/ 等字元,相較 Base64 來說更短,不保證唯一性。
  • URL-Safe Base64 是 Base64 編碼的變體,將其中的保留字元與填充字元替換以避免違反 URI 的格式規範,不保證唯一性。
  • SHA-256 雜湊 透過雜湊函數將長字串壓縮為固定長度,保證了唯一性。

其中適合短網址的編碼方式,主要為 Base58 編碼與 Base62 編碼,而 URL-Safe Base64 一般更常見於 API Token 或 JWT 中;當涉及需要具備唯一性的短網址或識別碼時,則會採用 SHA-256 雜湊。

不論是 Base58、Base62 還是 Base64 都是 確定性編碼(deterministic encoding) 方法,這意味著它滿足「相同輸入 → 相同輸出」及「不同輸入 → 不同輸出」,但不具備 唯一性。舉個例子:將同一個網址輸入給短網址服務,你認為縮短後的網址應該一樣嗎?為什麼?

唯一性不夠,拿 UUID 來湊

唯一性指的是每個編碼的結果都是獨一無二的,不會與其他值發生衝突,這在短網址服務、識別碼、加密貨幣地址等應用中特別重要。

在程式開發中,我們經常會使用具備高度唯一性的 UUID 或 GUID 來作為標識方式,或者資料庫中資料的主鍵(primary key),又或者是增量的 ID 來確保唯一性;前面提及 Base58、Base62 和 URL-Safe Base64 編碼並不能保證唯一性,而 SHA-256 雖然具備唯一性,但編碼後長度又顯得太長,那麼有什麼辦法呢?

答案想必你也知道了:「唯一性不夠,拿 UUID 來湊」,我們可以 使用 UUID 作為資料的主鍵(primary key),再使用 Base58 編碼將其轉換為辨識性高、長度不會太長,且理論上不會產生相同結果的字串

UUID 包含連接符號有 36 的字元長度,經 Base58 編碼後可以縮短至 22~24 個字元,並且不會有不易辨識的 I、l、O、0 等,這樣的處理方式十分適合作為短網址服務;除此之外,由於沒有了連接符號,滑鼠雙擊複製起來也更快一些。

當然啦!實際上在設計短網址服務時,採用增量 ID 搭配 Base58 編碼就能夠確保唯一性,並且生成的識別碼長度也較短;又或者是使用雜湊表與一組短碼進行映射,但這就不是本文想要探討的範圍了。

張貼留言