欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

基于Java設(shè)計(jì)一個(gè)短鏈接生成系統(tǒng)

 更新時(shí)間:2021年12月09日 08:50:00   作者:清朝程序猿  
相信大家在生活中會(huì)收到很多短信,而這些短信都有一個(gè)特點(diǎn)是鏈接很短。這些鏈接背后的原理是什么呢?怎么實(shí)現(xiàn)的?小編今天就帶你們詳細(xì)了解一下

引言

相信大家在生活中,特別是最近的雙十一活動(dòng)期間,會(huì)收到很多短信,而那些短信都有兩個(gè)特征,第一個(gè)是幾乎都是垃圾短信,這個(gè)特點(diǎn)此處可以忽略不計(jì),第二個(gè)特點(diǎn)是鏈接很短,比如下面這個(gè):

我們知道,短信有些是有字?jǐn)?shù)限制的,直接放一個(gè)帶滿各種參數(shù)的鏈接,不合適,另外一點(diǎn)是,不想暴露參數(shù)。好處無非以下:

  • 太長的鏈接容易被限制長度
  • 短鏈接看著簡潔,長鏈接看著容易懵
  • 安全,不想暴露參數(shù)
  • 可以統(tǒng)一鏈接轉(zhuǎn)換,當(dāng)然也可以實(shí)現(xiàn)統(tǒng)計(jì)點(diǎn)擊次數(shù)等操作

那背后的原理是什么呢?怎么實(shí)現(xiàn)的?讓你實(shí)現(xiàn)這樣的系統(tǒng),你會(huì)怎么設(shè)計(jì)呢?【來自于某鵝場面試官】

短鏈接的原理

短鏈接展示的邏輯

這里最重要的知識點(diǎn)是重定向,先復(fù)習(xí)一下http的狀態(tài)碼:

分類 含義
1** 服務(wù)器收到請求,需要請求者繼續(xù)執(zhí)行操作
2** 成功,操作被成功接收并處理
3** 重定向,需要進(jìn)一步的操作以完成請求
4** 客戶端錯(cuò)誤,請求包含語法錯(cuò)誤或無法完成請求
5** 服務(wù)器錯(cuò)誤,服務(wù)器在處理請求的過程中發(fā)生了錯(cuò)誤

那么以 3 開頭的狀態(tài)碼都是關(guān)于重定向的:

  • 300:多種選擇,可以在多個(gè)位置存在
  • 301:永久重定向,瀏覽器會(huì)緩存,自動(dòng)重定向到新的地址
  • 302:臨時(shí)重定向,客戶端還是會(huì)繼續(xù)使用舊的URL
  • 303:查看其他的地址,類似于301
  • 304:未修改。所請求的資源未修改,服務(wù)器返回此狀態(tài)碼時(shí),不會(huì)返回任何資源。
  • 305:需要使用代理才能訪問到資源
  • 306:廢棄的狀態(tài)碼
  • 307:臨時(shí)重定向,使用Get請求重定向

整個(gè)跳轉(zhuǎn)的流程:

1.用戶訪問短鏈接,請求到達(dá)服務(wù)器

2.服務(wù)器將短鏈接裝換成為長鏈接,然后給瀏覽器返回重定向的狀態(tài)碼301/302

301永久重定向會(huì)導(dǎo)致瀏覽器緩存重定向地址,短鏈接系統(tǒng)統(tǒng)計(jì)訪問次數(shù)會(huì)不正確

302臨時(shí)重定向可以解決次數(shù)不準(zhǔn)的問題,但是每次都會(huì)到短鏈接系統(tǒng)轉(zhuǎn)換,服務(wù)器壓力會(huì)變大。

3.瀏覽器拿到重定向的狀態(tài)碼,以及真正需要訪問的地址,重定向到真正的長鏈接上。

從下圖可以看出,確實(shí)鏈接被302重定向到新的地址上去,返回的頭里面有一個(gè)字段Location就是所要重定向的地址:

短鏈接怎么設(shè)計(jì)的

全局發(fā)號器

肯定我們第一點(diǎn)想到的是壓縮,像文件壓縮那樣,壓縮之后再解壓還原到原來的鏈接,重定向到原來的鏈接,但是很不幸的是,這個(gè)是行不通的,你有見過什么壓縮方式能把這么長的數(shù)字直接壓縮到這么短么?事實(shí)上不可能。就像是Huffman樹,也只能對那種重復(fù)字符較多的字符串壓縮時(shí)效率較高,像鏈接這種,可能帶很多參數(shù),而且各種不規(guī)則的情況都有,直接壓縮算法不現(xiàn)實(shí)。

那https://dx.10086.cn/tzHLFw與https://gd.10086.cn/gmccapp/webpage/payPhonemoney/index.html?channel=之間的裝換是怎么樣的呢?前面路徑不變,變化的是后面,也就是tzHLFw與gmccapp/webpage/payPhonemoney/index.html?channel=之間的轉(zhuǎn)換。

實(shí)際也很簡單,就是數(shù)據(jù)庫里面的一條數(shù)據(jù),一個(gè)id對應(yīng)長鏈接(相當(dāng)于全局的發(fā)號器,全局唯一的ID):

id url
1 gd.10086.cn/gmccapp/web…

這里用到的,也就是我們之前說過的分布式全局唯一ID,如果我們直接用id作為參數(shù),貌似也可以:https://dx.10086.cn/1,訪問這個(gè)鏈接時(shí),去數(shù)據(jù)庫查詢獲得真正的url,再重定向。

單機(jī)的唯一ID很簡單,用原子類AtomicLong就可以,但是分布式的就不行了,簡單點(diǎn)可以用 redis,或者數(shù)據(jù)庫自增,或者可以考慮Zookeeper之類的。

id 轉(zhuǎn)換策略

但是直接用遞增的數(shù)字,有兩個(gè)壞處:

  • 數(shù)字很大的時(shí)候,還是很長
  • 遞增的數(shù)字,不安全,規(guī)律性太強(qiáng)了

明顯我們平時(shí)看到的鏈接也不是數(shù)字的,一般都是大小寫字母加上數(shù)字。為了縮短鏈接的長度,我們必須把id轉(zhuǎn)換掉,比如我們的短鏈接由a-z,A-Z,0-9組成,相當(dāng)于62進(jìn)制的數(shù)字,將id轉(zhuǎn)換成為62進(jìn)制的數(shù)字:

public class ShortUrl {
 
    private static final String BASE = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
 
    public static String toBase62(long num) {
        StringBuilder result = new StringBuilder();
        do {
            int i = (int) (num % 62);
            result.append(BASE.charAt(i));
            num /= 62;
        } while (num > 0);
 
        return result.reverse().toString();
    }
 
    public static long toBase10(String str) {
        long result = 0;
        for (int i = 0; i < str.length(); i++) {
            result = result * 62 + BASE.indexOf(str.charAt(i));
        }
        return result;
    }
 
    public static void main(String[] args) {
        // tzHLFw
        System.out.println(toBase10("tzHLFw"));
        System.out.println(toBase62(27095455234L));
    }
}

id轉(zhuǎn) 62位的key 或者key裝換成為id都已經(jīng)實(shí)現(xiàn)了,不過計(jì)算還是比較耗時(shí)的,不如加個(gè)字段存起來,于是數(shù)據(jù)庫變成了:

id key url
27095455234 tzHLFw gd.10086.cn/gmccapp/web…

但是這樣還是很容易被猜出這個(gè)id和key的對應(yīng)關(guān)系,要是被遍歷訪問,那還是很不安全的,如果擔(dān)心,可以隨機(jī)將短鏈接的字符順序打亂,或者在適當(dāng)?shù)奈恢眉由弦恍╇S機(jī)生成的字符,比如第1,4,5 位是隨機(jī)字符,其他位置不變,只要我們計(jì)算的時(shí)候,將它對應(yīng)的關(guān)系存到數(shù)據(jù)庫,我們就可以通過連接的key找到對應(yīng)的url。(值得注意的是,key必須是全局唯一的,如果沖突,必須重新生成)

一般短鏈接都有過期時(shí)間,那么我們也必須在數(shù)據(jù)庫里面加上對應(yīng)的字段,訪問的時(shí)候,先判斷是否過期,過期則不給予重定向。

性能考慮

如果有很多短鏈接暴露出去了,數(shù)據(jù)庫里面數(shù)據(jù)很多,這個(gè)時(shí)候可以考慮使用緩存優(yōu)化,生成的時(shí)候順便把緩存寫入,然后讀取的時(shí)候,走緩存即可,因?yàn)橐话愣替溄雍烷L鏈接的關(guān)系不會(huì)修改,即使修改,也是很低頻的事情。

如果系統(tǒng)的id用完了怎么辦?這種概率很小,如果真的發(fā)生,可以重用舊的已經(jīng)失效的id號。

如果被人瘋狂請求一些不存在的短鏈接怎么辦?其實(shí)這就是緩存穿透,緩存穿透是指,緩存和數(shù)據(jù)庫都沒有的數(shù)據(jù),被大量請求,比如訂單號不可能為-1,但是用戶請求了大量訂單號為-1的數(shù)據(jù),由于數(shù)據(jù)不存在,緩存就也不會(huì)存在該數(shù)據(jù),所有的請求都會(huì)直接穿透到數(shù)據(jù)庫。如果被惡意用戶利用,瘋狂請求不存在的數(shù)據(jù),就會(huì)導(dǎo)致數(shù)據(jù)庫壓力過大,甚至垮掉。

針對這種情況,一般可以用布隆過濾器過濾掉不存在的數(shù)據(jù)請求,但是我們這里id本來就是遞增且有序的,其實(shí)我們范圍大致都是已知的,更加容易判斷,超出的肯定不存在,或者請求到的時(shí)候,緩存里面放一個(gè)空對象也是沒有問題的。

到此這篇關(guān)于基于Java設(shè)計(jì)一個(gè)短鏈接生成系統(tǒng)的文章就介紹到這了,更多相關(guān)Java短鏈接生成系統(tǒng)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論