小議短網址系統的設計(有些時候,需要換個角度思考問題)


前言

短網址,我想大家應該都見過,如果沒有,試着點擊下面這條鏈接 https://git.io/vSY4o,會跳到我的 GitHub 主頁,但是它確實比原始鏈接 https://github.com/hanzichi 要短了一些。關於短網址的作用,這里不作描述,本文主要講講如何實現一個簡單的短網址系統。

Leetcode 正好 有一題 與此有關,不妨一試。

思路

如果沒有接觸過短網址,不妨去 https://goo.gl/https://git.io/ 稍微體驗下。體驗的結果是,短網址都把網址壓縮成了六個字符,這是巧合嗎?

短網址整個運轉邏輯非常簡單,我們以 https://goo.gl/SfzlA2 為例,當我們訪問這個網址的時候,后端可以獲取 "SfzlA2" 這個字符串,然后跳轉到 https://github.com/hanzichi,很顯然,這個字符串和這個地址已經綁定,通過某種映射關系可以從 "SfzlA2" 獲取完整的地址。

那么,看起來我們只需要找到一個算法,能夠將一個長字符串壓縮成一個短的字符串,並且該算法應該是可逆的。但是實現這樣的文本壓縮算法,是非常困難的(不存在?),如果真有這么一個算法和逆運算,那么基本上現在的壓縮軟件都可以歇菜了,而世界上所有的信息(網址長度未知),都可以壓縮成固定長度個字符,這可能嗎?所以不要幻想使用壓縮算法,而且對於 URL 這種不超過 100 bytes 的字符串,壓縮算法的壓縮比通常都大於 1。

所以我們應該轉變思路。目前流行的短網址算法大概有兩種,一種是利用 md5,將長網址 md5 后,再進行分組壓縮,因為 md5 實質上是一種哈希算法,所以難免出現碰撞,當然,我們有解決哈希沖突的 N 種方法,但是這只會增加系統的復雜度,不推薦。另外一種是將網址和一個 62 進制數(0-9 & a-Z)對應,存入數據庫中,需要的時候,通過數據庫查詢提取。

實現

接着我們就根據以上的思路,來實現一個簡單的短網址系統。

我們先不考慮 62 進制的轉換,用 Map 來當做一個 k-v 的數據庫。當存入第一個網址的時候,假設我們的短網址是 xx.com/0,可以將 0 當做 key,將實際網址當做 value,需要查詢的時候直接提取,如果有新的短網址需要生成,將 key 自增。代碼如下。

let [p, index] = [new Map(), 0];

/**
 * Encodes a URL to a shortened URL.
 *
 * @param {string} longUrl
 * @return {string}
 */
var encode = function(longUrl) {
  p.set(index, longUrl);
  return index++;
};

/**
 * Decodes a shortened URL to its original URL.
 *
 * @param {string} shortUrl
 * @return {string}
 */
var decode = function(shortUrl) {
  return p.get(shortUrl);
};

很顯然,用一個 62 進制數表示,短網址可以更短。我們可以自己實現一個簡單的 10 進制到 62 進制的轉換算法。

let [p, index] = [new Map(), 0];

var base62 = (n) => {
  let str = '0123456789abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ';
  let len = str.length;
  let ret = '';

  do {
    ret += str[n % len];
    n = ~~(n / len);
  } while (n);

  return ret;
};

/**
 * Encodes a URL to a shortened URL.
 *
 * @param {string} longUrl
 * @return {string}
 */
var encode = function(longUrl) {
  let shortUrl = base62(index++);
  p.set(shortUrl, longUrl);
  return shortUrl;
};

/**
 * Decodes a shortened URL to its original URL.
 *
 * @param {string} shortUrl
 * @return {string}
 */
var decode = function(shortUrl) {
  return p.get(shortUrl);
};

這樣實現的話實際的短網址的數量其實是受限的,理論上應該是(JavaScript)能表示的最大的整數。

其他

這樣的實現,還有一些其他的問題,比如短網址的長度並不是固定的,這點容易解決,補位即可。再比如,這些短網址,按照順序排列,並不顯得隨機,這也好辦,比如可以隨機生成六位字符串當作 key,而不是用整數的遞增,這樣的話,短網址數量也不受限了(可以增加短網址位數)。還有一點,相同的 URL 可能得到不同的短網址,這點可以另外加個哈希或者用 Set 去解決,還可以加個緩存來解決(在緩存時間內,重定向到相同地址,一旦緩存失效,重新分配 key)。

除了算法設計外,真正的系統還需要考慮很多,比如發號器的設計,比如緩存(掛個 Redis),比如跳轉,等等,本文只是拋磚引玉,這些就留給你們自己去思考了。

短網址系統的設計,其實依賴的並不是文本壓縮算法。有些時候,需要換個角度思考問題

參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM