教你怎么實現(xiàn)縮短網(wǎng)址功能

本文將簡單介紹,如何去完成一個縮短網(wǎng)址的功能卵慰。

Node.js + MySQL + Redis版本的源碼地址:github

Demo地址:http://www.ecool.fun/shortLink

文章閱讀大概需要5分鐘沙郭。

什么是短鏈接

短鏈接,通俗來說裳朋,就是將長的URL網(wǎng)址病线,通過程序計算等方式,轉換為簡短的網(wǎng)址字符串鲤嫡。

大家經(jīng)乘吞簦可以從微博或者各類營銷短信中,看到短鏈接暖眼,形式一般類似于 t.cn/xxxxxx惕耕,點擊后,就能跳轉到對應的頁面诫肠。

早期短鏈接廣泛應用于圖片上傳網(wǎng)站司澎,通過縮短網(wǎng)址URL鏈接字數(shù),達到減少代碼字符串的目的栋豫。更便于使用者引用網(wǎng)址挤安,寫入代碼中,節(jié)省字符數(shù)空間丧鸯。常見于網(wǎng)店圖片分類的使用蛤铜,因有字符限制,運用短鏈接,達到外鏈圖片的目的围肥,自微博盛行以來剿干,在微博字數(shù)有限的特色下,短鏈接也盛行于微博網(wǎng)站虐先,以節(jié)省字數(shù)怨愤,給博主發(fā)布更多文字的空間。

將長鏈接轉成短鏈接蛹批,一般是為了方便記憶或者傳播。

需要完成的功能

從上面的介紹中篮愉,我們得出腐芍,縮短網(wǎng)址需要完成以下兩個功能點:

  • 將長網(wǎng)址縮短成短鏈接
  • 點擊生成短鏈接,能正常跳轉到原來的長網(wǎng)址頁面

全流程設計

其實上述功能點的原理很簡單试躏,簡單描述一下:

  • 用戶輸入長網(wǎng)址猪勇,服務端接收后進行處理,并根據(jù)長網(wǎng)址的內容颠蕴,生成一個短碼泣刹,并將映射關系進行存儲。然后根據(jù)短碼拼接出短鏈接犀被,返回給用戶椅您;
  • 用戶點擊短鏈接,服務器端根據(jù)短鏈接中的短碼寡键,查找到對應的長網(wǎng)址掀泳,并302跳轉到對應的頁面。

知識點:為什么要使用302跳轉西轩,而不是301跳轉呢员舵?

301是永久重定向,302是臨時重定向藕畔。短地址一經(jīng)生成就不會變化马僻,所以用301是符合http語義的。但是如果用了301注服, Google韭邓,百度等搜索引擎,搜索的時候會直接展示真實地址祠汇,那我們就無法統(tǒng)計到短地址被點擊的次數(shù)了仍秤,也無法收集用戶的Cookie, User Agent 等信息,這些信息可以用來做很多有意思的大數(shù)據(jù)分析可很,也是短網(wǎng)址服務商的主要盈利來源诗力。

引自知乎-武林的回答,原文鏈接

整個流程的設計如下圖所示:

短網(wǎng)址全流程

可以看到,我用到了MySQLRedis來存儲長網(wǎng)址和短碼之間的映射關系苇本。

MySQL想必大家都能理解袜茧,但是為什么要用 Redis 呢,直接用數(shù)據(jù)庫不就好了嗎瓣窄?

這個主要是考慮到生成短鏈接笛厦,在投放之后的訪問量會比較大,使用 Redis 緩存后俺夕,能有效降低數(shù)據(jù)庫的壓力裳凸。

生成短碼的方法

通過上面的全流程設計,會發(fā)現(xiàn)主要的問題就是如何通過長網(wǎng)址劝贸,去生成對應的短碼姨谷。

短碼一般是由 [a - z, A - Z, 0 - 9] 這62 個字母或數(shù)字組成,短碼的長度也可以自定義映九,但一般不超過8位梦湘。比較常用的都是6位,6位的短碼已經(jīng)能有568億種的組合:(26+26+10)^6 = 56800235584件甥,已滿足絕大多數(shù)的使用場景捌议。

目前比較流行的生成短碼方法有:自增id摘要算法引有、普通隨機數(shù)瓣颅。

  • 自增id

該方法是一種無碰撞的方法,原理是轿曙,每新增一個短碼弄捕,就在上次添加的短碼id基礎上加1,然后將這個10進制的id值导帝,轉化成一個62進制的字符串守谓。

一般利用數(shù)據(jù)表中的自增id來完成:每次先查詢數(shù)據(jù)表中的自增id最大值max,那么需要插入的長網(wǎng)址對應自增id值就是 max+1您单,將max+1轉成62進制即可得到短碼斋荞。

但是短碼 id 是從一位長度開始遞增,短碼的長度不固定虐秦,不過可以用 id 從指定的數(shù)字開始遞增的方式來處理平酿,確保所有的短碼長度都一致。同時悦陋,生成的短碼是有序的蜈彼,可能會有安全的問題,可以將生成的短碼id俺驶,結合長網(wǎng)址等其他關鍵字幸逆,進行md5運算生成最后的短碼。

10進制轉成62進制的具體實現(xiàn):

function string10to62(number) {
    const chars = '0123456789abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ';
    const charsArr = chars.split('');
    const radix = chars.length;
    let qutient = +number;
    let arr = [];
    do{
        let mod = qutient % radix;
        qutient = (qutient - mod) / radix;
        arr.unshift(charsArr[mod]);
    }while(qutient);
    return arr.join('');
}
  • 摘要算法

摘要算法又稱哈希算法,它表示輸入任意長度的數(shù)據(jù)还绘,輸出固定長度的數(shù)據(jù)楚昭。相同的輸入數(shù)據(jù)始終得到相同的輸出,不同的輸入數(shù)據(jù)盡量得到不同的輸出拍顷。

算法思路:

1抚太、將長網(wǎng)址通過 md5 運算,生成 32 字符的 hex string昔案,分為 4 段尿贫,每段 8 個字符;

2爱沟、對這四段循環(huán)處理帅霜,取 8 個字節(jié),將其看成 16 進制串呼伸,并與 0x3fffffff(30位1) 與操作,即超過 30 位的忽略處理钝尸;

3括享、這 30 位分成 6 段,每 5 位的數(shù)字作為字母表的索引取得特定字符珍促,依次進行獲得 6 位字符串铃辖。

4、總的 md5 串可以獲得 4 個 6 位串猪叙,取里面的任意一個就可作為這個長網(wǎng)址的短鏈接 url 地址娇斩。

雖然幾率很小,但是該方法依然存在碰撞的可能性穴翩,解決沖突會比較麻煩犬第。不過該方法生成的短碼位數(shù),是固定的芒帕,也不存在連續(xù)生成的短碼有序的情況歉嗓。

  • 普通隨機數(shù)

該方法是從62個字符串中隨機取出一個6位短碼的組合,然后去數(shù)據(jù)庫中查詢該短碼是否已存在背蟆。如果已存在鉴分,就繼續(xù)循環(huán)該方法重新獲取短碼,否則就直接返回带膀。

該方法是最簡單的一種實現(xiàn)志珍,不過由于Math.round()方法生成的隨機數(shù)屬于偽隨機數(shù),碰撞的可能性也不小垛叨。在數(shù)據(jù)比較多的情況下伦糯,可能會循環(huán)很多次,才能生成一個不沖突的短碼。

具體實現(xiàn):

// 獲取唯一的Link
async getShortLink() {
    const shortLink = this.generateShortLink();

    // 查詢數(shù)據(jù)庫中是否存在該鏈接舔株,如果存在莺琳,就直接返回
    const searchResult = await this.searchByLinkInMySQL(shortLink);

    if (searchResult && searchResult.length > 0) {
    // 如果shortLink已經(jīng)存在,就遍歷重新生成
        return this.getShortLink();
    }
    return shortLink;

}

// 生成隨機的Link
generateShortLink() {
    let str = '';
    const arr = [
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
    ];

    for (let i = 0; i < 6; i++) {
        const pos = Math.round(Math.random() * (arr.length - 1));
        str += arr[pos];
    }
    return str;
}

綜上载慈,比較推薦使用第一種方法來實現(xiàn)短碼的生成惭等。

廣告時間

最后,歡迎大家star我們的人人貸大前端團隊博客办铡,所有的文章還會同步更新到知乎專欄掘金賬號辞做,我們每周都會分享幾篇高質量的大前端技術文章。

參考文章

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市童叠,隨后出現(xiàn)的幾起案子框喳,更是在濱河造成了極大的恐慌,老刑警劉巖厦坛,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件五垮,死亡現(xiàn)場離奇詭異,居然都是意外死亡杜秸,警方通過查閱死者的電腦和手機放仗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來撬碟,“玉大人诞挨,你說我怎么就攤上這事∧馗颍” “怎么了惶傻?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長顾稀。 經(jīng)常有香客問我达罗,道長,這世上最難降的妖魔是什么静秆? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任粮揉,我火速辦了婚禮,結果婚禮上抚笔,老公的妹妹穿的比我還像新娘扶认。我一直安慰自己,他們只是感情好殊橙,可當我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布辐宾。 她就那樣靜靜地躺著狱从,像睡著了一般。 火紅的嫁衣襯著肌膚如雪叠纹。 梳的紋絲不亂的頭發(fā)上季研,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天,我揣著相機與錄音誉察,去河邊找鬼与涡。 笑死,一個胖子當著我的面吹牛持偏,可吹牛的內容都是我干的驼卖。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼鸿秆,長吁一口氣:“原來是場噩夢啊……” “哼酌畜!你這毒婦竟也來了?” 一聲冷哼從身側響起卿叽,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤桥胞,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后考婴,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體埠戳,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年蕉扮,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片颗圣。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡喳钟,死狀恐怖,靈堂內的尸體忽然破棺而出在岂,到底是詐尸還是另有隱情奔则,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布蔽午,位于F島的核電站易茬,受9級特大地震影響,放射性物質發(fā)生泄漏及老。R本人自食惡果不足惜抽莱,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望骄恶。 院中可真熱鬧食铐,春花似錦、人聲如沸僧鲁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽抡诞。三九已至,卻和暖如春偶惠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背朗涩。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工忽孽, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人馋缅。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓扒腕,卻偏偏與公主長得像,于是被迫代替她去往敵國和親萤悴。 傳聞我的和親對象是個殘疾皇子瘾腰,可洞房花燭夜當晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內容