面試必備:如何將一個(gè)長(zhǎng)URL轉(zhuǎn)換為一個(gè)短URL?
一、前言
前幾天整理面試題的時(shí)候,有一道試題是《如何將一個(gè)很長(zhǎng)的URL轉(zhuǎn)換為一個(gè)短的URL,并實(shí)現(xiàn)他們之間的相互轉(zhuǎn)換?》,現(xiàn)在想起來(lái)這是一個(gè)絕對(duì)不簡(jiǎn)單的問(wèn)題,需要考慮很多方面,今天和大家一起學(xué)習(xí)研究一下!
短網(wǎng)址:顧名思義,就是將長(zhǎng)網(wǎng)址縮短到一個(gè)很短的網(wǎng)址,用戶訪問(wèn)這個(gè)短網(wǎng)址可以重定向到原本的長(zhǎng)網(wǎng)址(也就是還原的過(guò)程)。這樣可以達(dá)到易于記憶、轉(zhuǎn)換的目的,常用于有字?jǐn)?shù)限制的微博、二維碼等等場(chǎng)景。
關(guān)于短URL的使用場(chǎng)景,舉個(gè)簡(jiǎn)單的例子來(lái)說(shuō)明一下,看一下業(yè)務(wù)中使用短URL的重要性!
二、短地址使用場(chǎng)景
1、新浪微博
我們?cè)谛吕宋⒉┥习l(fā)布網(wǎng)址的時(shí)候,微博會(huì)自動(dòng)判別網(wǎng)址,并將其轉(zhuǎn)換,例如:https://t.cn/RuPKzRW。為什么要這樣做的?
這是因?yàn)槲⒉┫拗谱謹(jǐn)?shù)為140字一條,那么如果我們需要發(fā)一些鏈接上去,但是這個(gè)鏈接非常的長(zhǎng),以至于將近要占用我們內(nèi)容的一半篇幅,這肯定是不能被允許的或者說(shuō)用戶體驗(yàn)很差的,所以短網(wǎng)址應(yīng)運(yùn)而生了,短網(wǎng)址這種服務(wù)可以說(shuō)是在微博出現(xiàn)之后才流行開(kāi)來(lái)的!往下看:
(1)首先,我先發(fā)一條微博帶有一個(gè)URL地址:
(2)然后,看他轉(zhuǎn)換之后顯示的效果是什么樣子的哪?
(3)查看對(duì)應(yīng)頁(yè)面元素的HTML源碼如下:
(4)可以看出:https://blog.csdn.net/xlgen157387/article/details/79863301 被轉(zhuǎn)換為:http://t.cn/RuPKzRW,此時(shí)你訪問(wèn)http://t.cn/RuPKzRW是可以定位到https://blog.csdn.net/xlgen157387/article/details/79863301,也就是實(shí)現(xiàn)了轉(zhuǎn)換。
2、短網(wǎng)址二維碼
網(wǎng)址在轉(zhuǎn)換成短網(wǎng)址時(shí),也可以生成相應(yīng)的短網(wǎng)址二維碼,短網(wǎng)址二維碼的應(yīng)用,二維碼核心解決的是跨平臺(tái)、跨現(xiàn)實(shí)的數(shù)據(jù)傳輸問(wèn)題;而且二維碼跟應(yīng)用場(chǎng)景結(jié)合之后,所能解決的問(wèn)題會(huì)越來(lái)越多。
(1)短網(wǎng)址二維碼相比短鏈接更方便,能少輸入,盡量少輸入,哪怕只是少點(diǎn)一下鍵盤,都是有意義的。
(2)二維碼只是掃描一個(gè)簡(jiǎn)單的鏈接,打開(kāi)的卻是一個(gè)世界。想象一下,用手機(jī)購(gòu)買售貨機(jī)里商品,二維碼掃描是略快于從用手機(jī)找到該售貨機(jī)并找到該商品的,而且這種操作相對(duì)于搜索/查找而言不是更優(yōu)雅嗎?
(3)所有商超里面的商品,都是使用條碼來(lái)確定商品的***性的,去買單的時(shí)候都是掃描條碼。試想,如果里面加入了更多產(chǎn)品的生產(chǎn)日期、廠家、流轉(zhuǎn)途徑、原材料等等信息,是不是厲害了呢?特別是針對(duì)食品信息的可追溯上,二維碼應(yīng)用場(chǎng)景更廣泛。
三、短地址的好處
除了上述場(chǎng)景中,我們將長(zhǎng)地址轉(zhuǎn)換為短地址的使用場(chǎng)景的優(yōu)點(diǎn)(壓縮URL長(zhǎng)度)之外,短地址還具有很多實(shí)際場(chǎng)景中的優(yōu)點(diǎn),例如:
(1)節(jié)省網(wǎng)址長(zhǎng)度,便于社交化傳播,一個(gè)是讓URL更短小,傳播更方便,尤其是URL中有中文和特殊字符,短網(wǎng)址解決很長(zhǎng)的URL難以記憶不利于傳播的問(wèn)題;
(2)短網(wǎng)址在我們項(xiàng)目里可以很好的對(duì)開(kāi)放以及對(duì)URL進(jìn)行管理。有一部分網(wǎng)址可以會(huì)涵蓋性、暴力、廣告等信息,這樣我們可以通過(guò)用戶的舉報(bào),完全管理這個(gè)連接將不出現(xiàn)在我們的應(yīng)用中,對(duì)同樣的URL通過(guò)加密算法之后,得到的地址是一樣的;
(3)方便后臺(tái)跟蹤點(diǎn)擊量、地域分布等用戶統(tǒng)計(jì)。我們可以對(duì)一系列的網(wǎng)址進(jìn)行流量,點(diǎn)擊等統(tǒng)計(jì),挖掘出大多數(shù)用戶的關(guān)注點(diǎn),這樣有利于我們對(duì)項(xiàng)目的后續(xù)工作更好的作出決策;
(4)規(guī)避關(guān)鍵詞、域名屏蔽手段、隱藏真實(shí)地址,適合做付費(fèi)推廣鏈接;
(5)當(dāng)你看到一個(gè)淘寶的寶貝連接后面是200個(gè)“e7x8bv7c8bisdj”這樣的字符的時(shí)候,你還會(huì)覺(jué)得舒服嗎。更何況微博字?jǐn)?shù)只有140字,微博或短信里,字?jǐn)?shù)不夠,你用條短網(wǎng)址就能幫你騰出很多空間來(lái);
四、短網(wǎng)址服務(wù)提供平臺(tái)
目前,國(guó)內(nèi)網(wǎng)又很多提供短地址服務(wù)的平臺(tái),例如:
- 新浪:http://sina.lt/
- 百度:http://dwz.cn/
- 0x3:http://0x3.me/
- MRW:http://mrw.so/
等等還有很多,這個(gè)可以搜索一下就會(huì)有很多!但是一個(gè)注意的是,如果使用某一個(gè)平臺(tái)的短地址服務(wù),一定要保證長(zhǎng)期可靠的服務(wù),不然一段時(shí)間失效了,我們以前已經(jīng)轉(zhuǎn)換的URL就完了!
這里以百度例,將我們上述博客的地址轉(zhuǎn)換為短地址如下所示:
當(dāng)然,對(duì)于我們的業(yè)務(wù)來(lái)說(shuō),如果自己可以提供自己的短URL服務(wù)那才是更好的,不需要受制于人!(中國(guó)芯片需要崛起?。。。?/p>
五、關(guān)于如何生成短地址URL的討論
關(guān)于短地址URL如何生成方式的,網(wǎng)上有很多方式,有基于映射的,有基于Hash的,有基于簽名的,但是總的來(lái)說(shuō)并不能滿足絕大部分場(chǎng)景的使用,或者說(shuō)是一種錯(cuò)誤的設(shè)計(jì)方式。這里不再重復(fù)造輪子!以下是知乎用戶iammutex關(guān)于該問(wèn)題的探討,截圖過(guò)來(lái)和大家一起學(xué)習(xí)一下:
六、生成短地址URL需要注意的
看到上述知乎用戶iammutex關(guān)于如何正確生成短地址URL的探討,我們知道了,可以通過(guò)發(fā)號(hào)器的方式正確的生成短地址,生成算法設(shè)計(jì)要點(diǎn)如下:
(1)利用放號(hào)器,初始值為0,對(duì)于每一個(gè)短鏈接生成請(qǐng)求,都遞增放號(hào)器的值,再將此值轉(zhuǎn)換為62進(jìn)制(a-zA-Z0-9),比如***次請(qǐng)求時(shí)放號(hào)器的值為0,對(duì)應(yīng)62進(jìn)制為a,第二次請(qǐng)求時(shí)放號(hào)器的值為1,對(duì)應(yīng)62進(jìn)制為b,第10001次請(qǐng)求時(shí)放號(hào)器的值為10000,對(duì)應(yīng)62進(jìn)制為sBc。
(2)將短鏈接服務(wù)器域名與放號(hào)器的62進(jìn)制值進(jìn)行字符串連接,即為短鏈接的URL,比如:t.cn/sBc。
(3)重定向過(guò)程:生成短鏈接之后,需要存儲(chǔ)短鏈接到長(zhǎng)鏈接的映射關(guān)系,即sBc -> URL,瀏覽器訪問(wèn)短鏈接服務(wù)器時(shí),根據(jù)URL Path取到原始的鏈接,然后進(jìn)行302重定向。映射關(guān)系可使用K-V存儲(chǔ),比如Redis或Memcache。
七、生成短地址之后如何跳轉(zhuǎn)哪?
對(duì)于該部分的討論,我們可以認(rèn)為他是整個(gè)交互的流程,具體的流程細(xì)節(jié)如下:
(1)用戶訪問(wèn)短鏈接:http://t.cn/RuPKzRW;
(2)短鏈接服務(wù)器t.cn收到請(qǐng)求,根據(jù)URL路徑RuPKzRW獲取到原始的長(zhǎng)鏈接(KV緩存數(shù)據(jù)庫(kù)中去查找):https://blog.csdn.net/xlgen157387/article/details/79863301;
(3)服務(wù)器返回302狀態(tài)碼,將響應(yīng)頭中的Location設(shè)置為:https://blog.csdn.net/xlgen157387/article/details/79863301;
(4)瀏覽器重新向https://blog.csdn.net/xlgen157387/article/details/79863301發(fā)送請(qǐng)求;
(5)返回響應(yīng);
八、短地址發(fā)號(hào)器優(yōu)化方案
1、算法優(yōu)化
采用以上算法,如果不加判斷,那么即使對(duì)于同一個(gè)原始URL,每次生成的短鏈接也是不同的,這樣就會(huì)浪費(fèi)存儲(chǔ)空間(因?yàn)樾枰鎯?chǔ)多個(gè)短鏈接到同一個(gè)URL的映射),如果能將相同的URL映射成同一個(gè)短鏈接,這樣就可以節(jié)省存儲(chǔ)空間了。主要的思路有如下兩個(gè):
方案1:查表
每次生成短鏈接時(shí),先在映射表中查找是否已有原始URL的映射關(guān)系,如果有,則直接返回結(jié)果。很明顯,這種方式效率很低。
方案2:使用LRU本地緩存,空間換時(shí)間
使用固定大小的LRU緩存,存儲(chǔ)最近N次的映射結(jié)果,這樣,如果某一個(gè)鏈接生成的非常頻繁,則可以在LRU緩存中找到結(jié)果直接返回,這是存儲(chǔ)空間和性能方面的折中。
2、可伸縮和高可用
如果將短鏈接生成服務(wù)單機(jī)部署,缺點(diǎn)一是性能不足,不足以承受海量的并發(fā)訪問(wèn),二是成為系統(tǒng)單點(diǎn),如果這臺(tái)機(jī)器宕機(jī)則整套服務(wù)不可 用,為了解決這個(gè)問(wèn)題,可以將系統(tǒng)集群化,進(jìn)行“分片”。
在以上描述的系統(tǒng)架構(gòu)中,如果發(fā)號(hào)器用Redis實(shí)現(xiàn),則Redis是系統(tǒng)的瓶頸與單點(diǎn),因此,利用數(shù)據(jù)庫(kù)分片的設(shè)計(jì)思想,可部署多個(gè)發(fā)號(hào)器實(shí)例,每個(gè)實(shí)例負(fù)責(zé)特定號(hào)段的發(fā)號(hào),比如部署10臺(tái)Redis,每臺(tái)分別負(fù)責(zé)號(hào)段尾號(hào)為0-9的發(fā)號(hào),注意此時(shí)發(fā)號(hào)器的步長(zhǎng)則應(yīng)該設(shè)置為10(實(shí)例個(gè)數(shù))。
另外,也可將長(zhǎng)鏈接與短鏈接映射關(guān)系的存儲(chǔ)進(jìn)行分片,由于沒(méi)有一個(gè)中心化的存儲(chǔ)位置,因此需要開(kāi)發(fā)額外的服務(wù),用于查找短鏈接對(duì)應(yīng)的原始鏈接的存儲(chǔ)節(jié)點(diǎn),這樣才能去正確的節(jié)點(diǎn)上找到映射關(guān)系。
九、如何用代碼實(shí)現(xiàn)短地址
說(shuō)到這里終于說(shuō)到重點(diǎn)了,很多小伙伴已經(jīng)按捺不住了,不好意思讓大家失望了,這只是一片簡(jiǎn)單的文章,并不能把這么繁雜的一個(gè)系統(tǒng)演示清楚!秉著不要重復(fù)造輪子的原則,這里給出一個(gè)為數(shù)不多還算可以的實(shí)現(xiàn)短地址的開(kāi)源項(xiàng)目:urlshorter
注意:urlshorter本身還是基于隨機(jī)的方式生成短地址的,并不算是一個(gè)短地址發(fā)號(hào)器,因此會(huì)有性能問(wèn)題和沖突的出現(xiàn),和知乎用戶iammutex 描述的實(shí)現(xiàn)方式還是有區(qū)別的!而關(guān)于短地址發(fā)號(hào)器的方式目前還沒(méi)有找到更好的開(kāi)源項(xiàng)目可供參考!
項(xiàng)目地址:https://gitee.com/tinyframework/urlshorter
十、總結(jié)
到此為止,我們一起學(xué)習(xí)了什么是短地址,短地址的優(yōu)點(diǎn),如何選擇一種正確的方式來(lái)實(shí)現(xiàn)我們的短地址,以及在碼云上找到的一個(gè)還算可以的短地址生成項(xiàng)目,相信此時(shí)的你能夠有一個(gè)更好的了解!