最通俗易懂的短鏈接原理講解
看業務代碼的時候,有些邏輯用到了短鏈接服務,感覺還蠻有意思的,這裏簡單的記錄一下。
這種營銷短信大家應該都收到過,短信有最大字符限制,而且爲了更好的觀感體驗,短信裏的鏈接一般都很短。現成的短鏈接生成服務也比較多,比如新浪、百度等,谷歌之前也有短鏈接服務,號稱是最快的,但是在 2018 年關閉了。
一、短鏈接原理
我們點擊短鏈接會發起一個 GET 方式的 HTTP 請求,當請求到對應的 API 後,會解析短鏈接裏的標識獲取到對應的長鏈接,然後重定向到長鏈接,這樣整個流程就結束了。
比如我用新浪的短鏈接服務爲 https://www.google.com/ 生成了一個短鏈接:http://dwz.date/evn,下面是請求短鏈接時對應的 HTTP 信息:
二、短鏈接生成算法
短鏈接標識一般是 [0-9, a-z, A-Z] 隨機組合而成的字符串,字符一共有 62 個,因此短鏈接標識可以用 62 進制的字符串表示。
首先維護一個自增的 ID,當生成短鏈接時,將 10 進制的自增 ID 轉換成 62 進制字符串,這個字符串就可以唯一標識一個長鏈接。由於 ID 是自增的,對應的 62 進制字符串是不同的,這樣就不會出現一個短鏈接對應多個長鏈接的問題,62 個字符排列組合,可以保證短鏈接是用不完的,就算僅限於 6 位長度標識的短鏈接,也有 558 億多種情況,這種算法在網上被稱爲自增序列算法。
維護自增 ID 主要有以下幾種方式:
- 數據庫主鍵自增
- redis 自增
- 分佈式自增主鍵 ID(雪花算法,存在 ID 浪費)
下面是 62 進制的 encode 與 decode 方法,來自 Base62。
private static String base62(Long b10) {
StringBuilder ret = new StringBuilder();
while (b10 > 0) {
ret.insert(0, characters.charAt((int) (b10 % 62)));
b10 /= 62;
}
return ret.toString();
}
private static long decodeBase62(String b62) {
long ret = 0;
b62 = new StringBuffer(b62).reverse().toString();
long count = 1;
for (char character : b62.toCharArray()) {
ret += characters.indexOf(character) * count;
count *= 62;
}
return ret;
}
三、一些細節
- 自增序列算法也存在一定的缺點,當自增主鍵很大時,生成的 62 進制字符串會變長,以
0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
順序的 62 進製爲例,當主鍵大於 56800235583 時,會生成 7 位長度的 62 進制字符串。這個問題可以通過控制自增主鍵的增長速度來解決,而且要避免主鍵浪費。 - 62 進制的順序並不一定嚴格按照
0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
的順序來表示,這個順序可以是打亂的,這樣生成的短鏈接標識更隨機不易被破解。 - 長鏈接與短鏈接是否需要一對多關係,同一個長鏈接使用自增主鍵 ID 算法生成的短鏈接是不同的,因爲自增主鍵 ID 不同,生成的 62 進制字符串自然也不同。如果我們有一個長鏈接唯一對應一個短鏈接需求,可以將長鏈接進行 md5 加密,將加密後的 md5 值存儲在 DB 中,每次生成短鏈接前都根據長鏈接 md5 值查詢 DB,如果存在,則直接返回短鏈接,當然也可以使用其他方式維護這種關係。
- 跳轉用 301 還是 302,301 永久重定向,302 是臨時重定向。短地址一經生成就不會變化,所以用 301 是符合 http 語義的。同時對服務器壓力也會有一定減少。
但是如果使用了 301,我們就無法統計到短地址被點擊的次數了。而這個點擊次數是一個非常有意思的大數據分析數據源。能夠分析出的東西非常非常多。所以選擇 302 雖然會增加服務器壓力,但是我想是一個更好的選擇。from 短 URL 系統是怎麼設計的? by iammutex - 如果短鏈接請求頻繁,可以藉助 redis 做對應的緩存優化。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://blog.csdn.net/codejas/article/details/106102452