跳至主要内容

1 篇文章 含有標籤「hash-function」

檢視所有標籤

短網址設計

· 閱讀時間約 4 分鐘
balnibarbian

短網址的核心目標,是用有限字元表達最多的唯一值。本篇釐清常見的三種生成思路,並談碰撞、資訊洩漏與可追蹤性的差異。

hash function

把原始 URL 投射到如 SHA256 或 MD5 的雜湊值,再取前面幾個字元做為短網址。這種做法的好處是每次只要有 URL 就能快速產生對應值,不需先寫入資料庫即可比較是否重複。但缺點也很明顯:

  • 縮短後缺乏唯一性保證,必須加上碰撞檢查與重試邏輯。
  • 雜湊值仍承載原始 URL 的資訊片段,理論上可供暴力逆推(尤其選用太短時)。
  • 無法表示建立順序、也不易追蹤來源,對一些流量分析情境不友善。

若需求是臨時、開發測試用的短網址,hash 方案能快速上手;但正式服務需要加強碰撞處理與 idempotency,才能避免重複導向。

id + base62

最常見的方式是讓資料庫自增 id,再把值轉成 base62(0-9a-zA-Z)。成品的特徵如下:

  • 唯一性:只要 id 不會重複,短網址就一定獨一無二。
  • 可逆性:只要能轉回 base62,就能還原 id,進一步查出原始 URL。
  • 長度可控:可以預先規劃 id 的最大範圍,轉成 base62 之後落在 6~8 個字元內。

缺點是需要中心化的資料庫或序列器來協調 id 的分配。若要擴展到多個節點,有額外的分區或跨節點同步成本。此外,字串會隨時間遞增,若想躲避暴露資料量或流量模式,就需要加些混淆手法。

snowflake / uuidv7 + base62

進階系統會採用分散式序列產生器,例如 Twitter 的 snowflake 或新的 uuidv7,它們把時間戳、節點編號、序號組合起來,再轉成 base62。這類方案的優勢包括:

  • 分散式:各節點可以獨立生成 id,不需集中鎖定。
  • 可排序:產生順序可反映時間(尤其 uuidv7 與 snowflake 的時間前綴)。
  • 長度合理、碰撞機率接近零。

將這種 id 再 encode 成 base62,就能在不犧牲可排序性的前提下得到可分享的短網址。如果想更短,可以只取時間戳與序號部分、再加 checksum,降低使用者手動輸入錯誤的風險。這類做法適合高吞吐、跨區域部署或需要追蹤來源的產品級服務。

整體架構要素

可以把短網址系統想成兩層:儲存層負責維護短碼與原始 URL 的對應,邏輯層負責產生 id、判斷歸戶、追蹤與排程。常見的架構要素包括:

  • 資料表設計:主表 short_links 包含 idshort_codetarget_urlcreator_idcreated_atexpires_atstatus(例如 active/disabled)、usage_countlast_accessed_at。若衍生功能如 A/B 測試或廣告導流,可再加 campaign_idvariant_tag。建議以 short_code 為唯一索引,加速查找。
  • 解析與 redirect:解析層收到短碼後,先查資料並更新 usage_count/last_accessed_at,再回傳 302 redirect 到 target_url。這個流程可以部署在 edge 或 CDN 層,盡量維持低延遲;複雜的條件(驗證、廣告插頁)可交由後端服務處理。
  • HTTP 狀態選擇:302(Found)是常見選擇,即使施工中也能快速改回原 URL。若希望搜尋引擎自然索引原址,改用 301(Moved Permanently)。對於可能要調整的短網址,分別設定 redirect_type 欄位控制返回值。
  • 快取與同步:由於查表頻率高,配合 Redis/L1 cache 快取 short_code -> target_url,並設定 TTL。若有分散寫入,應設計事件或 stream(Kafka/Change Data Capture)同步至快取節點以免 stale。
  • 廣告與觀察:若要放廣告或橫幅頁面,可以在 redirect 前插入檢查,例如 campaign_id 决定是否先導至吸引頁、再透過 client-side script 紀錄曝光後跳轉。也可在 short_linkslanding_page_html 選項,讓某些短碼呈現自訂落地頁再跳轉。
  • 追蹤與安全:加入 referer/utm 欄位、IP 黑名單、rate limit,讓濫用時能降載。另外可以記錄 fingerprintuser_agent 供分析使用頻率與地域。

總結

若是單機、初期方案,id + base62 提供簡單可逆、長度易控的產出;想快速實驗或不想自己維護序列器,就可考慮 hash function(記得補上碰撞處理與 retry)。若系統將來會分散部署、需排序或高可用,snowflake / uuidv7 + base62 是比較周全的選項。也可以混搭,例如用 uuidv7 生成原始 id,再 encode 成 base62,最後加 checksum,兼顧易讀與健壯性。整體架構應涵蓋儲存表、快取、redirect 處理、狀態控制與廣告/觀察擴充,才能支援不同使用情境。