日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

长URL链接转短链接算法

發布時間:2023/12/14 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 长URL链接转短链接算法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

引言

很多大型網站都加入了短鏈接的功能。之所以要是使用短鏈接,主要是因為微博只允許發140 字,如果鏈接地址太長的話,那么發送的字數將大大減少。短鏈接的主要職責就是把原始鏈接很長的地址壓縮成只有6 個字母的短鏈接地址,當我們點擊這6 個字母的鏈接后,我們又可以跳轉到原始鏈接地址。

開始以為短鏈接是按照某種算法把原始鏈接壓縮為短鏈接,再根據算法從短鏈接反算成原始鏈接的。后來嘗試了下壓縮算法(比如gzip 壓縮算法),發現對于url 這種字符串越是壓縮,長度就越長。通過對壓縮算法的一些了解,發現靠壓縮算法來實現這個功能不太靠譜。

后來在網上找到一個生成算法,該算法主要使用MD5 算法對原始鏈接進行加密(這里使用的MD5 加密后的字符串長度為32 位),然后對加密后的字符串進行處理以得到短鏈接的地址。

原始的算法是C 版本的,這里我把該算法修改成Java 版本的. 算法的具體代碼如下,代碼中有注釋:

代碼

public class ShortUrlGenerator {/*** @param args*/public static void main(String[] args) {// 長連接: http://tech.sina.com.cn/i/2011-03-23/11285321288.shtml// 新浪解析后的短鏈接為: http://t.cn/h1jGSCString sLongUrl = "http://tech.sina.com.cn/i/2011-03-23/11285321288.shtml" ; // 3BD768E58042156E54626860E241E999String[] aResult = shortUrl (sLongUrl);// 打印出結果for ( int i = 0; i < aResult. length ; i++) {System. out .println( "[" + i + "]:::" + aResult[i]);}}public static String[] shortUrl(String url) {// 可以自定義生成 MD5 加密字符傳前的混合 KEYString key = "wuguowei" ;// 要使用生成 URL 的字符String[] chars = new String[] { "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" , "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"};// 對傳入網址進行 MD5 加密String sMD5EncryptResult = ( new MD5()).getMD5ofStr(key + url);String hex = sMD5EncryptResult;String[] resUrl = new String[4];for ( int i = 0; i < 4; i++) {// 把加密字符按照 8 位一組 16 進制與 0x3FFFFFFF 進行位與運算String sTempSubString = hex.substring(i * 8, i * 8 + 8);// 這里需要使用 long 型來轉換,因為 Inteper .parseInt() 只能處理 31 位 , 首位為符號位 , 如果不用 long ,則會越界long lHexLong = 0x3FFFFFFF & Long.parseLong (sTempSubString, 16);String outChars = "" ;for ( int j = 0; j < 6; j++) {// 把得到的值與 0x0000003D 進行位與運算,取得字符數組 chars 索引long index = 0x0000003D & lHexLong;// 把取得的字符相加outChars += chars[( int ) index];// 每次循環按位右移 5 位lHexLong = lHexLong >> 5;}// 把字符串存入對應索引的輸出數組resUrl[i] = outChars;}return resUrl;}}

輸出結果

執行上面代碼的結果如下,會產生4 組6 位字符串,任意一組都可以作為當前字符串的短鏈接地址。

[0]:::7nUFJn [1]:::f6Zzy2 [2]:::j6jmQb [3]:::2eAjea

跳轉原理

當我們生成短鏈接之后,只需要在表中(數據庫或者NoSql )存儲原始鏈接與短鏈接的映射關系即可。當我們訪問短鏈接時,只需要從映射關系中找到原始鏈接,即可跳轉到原始鏈接。

參考

  • 調用第三方接口自動轉
  • springboot 實現長鏈接轉短鏈接轉換原理: 將原url通過一系列方式,轉換成6位短碼(只要能不重復,隨便怎么方式都行);將長短鏈接存入數據庫,形成一條對應關系;訪問短鏈接的時候,在數據庫找到對應的長鏈接,并通過重定向實現原url的訪問;(如果你的轉換方式能過還原,也可以不要數據庫,但必須保證轉換后的短碼不能重復)(代碼部分和正文部分一樣的算法)**缺點:**這個index的取值范圍額只有32個,永遠不可能是 2、3、6、7、10、11… 。所以自己重新寫一個算法。
  • 改進2的算法算法的步驟如下: 對Url進行md5編碼,對md5碼進行base64編碼,長度為22剔除base64碼中的‘+’和‘/’, 取前面的一段,如果位數不夠,用base64碼加上url再進行一次md5,用這個補齊,循環4直到位數滿足短碼的長度需求

  • 網上還有很多算法,比如:自增長算法(這個可能存在增長鎖的問題),隨機數算法。按理來說都是可行的,但是這些算法無法去重,就是可能會出現一個url在對應表中有多條記錄。用上面基于Md5的算法,可以解決這個問題。在發現編碼存在時進一步核實原始url是否一致,如果一致就不是沖突。

    最爛的回答

    實現一個算法,將長地址轉成短地址。實現長和短一一對應。然后再實現它的逆運算,將短地址還能換算回長地址。

    這個回答看起來挺完美的,然后候選人也會說現在時間比較短,如果給我時間我去找這個算法就解決問題了。但是稍微有點計算機或者信息論常識的人就能發現,這個算法就跟永動機一樣,是永遠不可能找到的。即使我們定義短地址是100位。那么它的變化是62的100次方。62=10數字+26大寫字母+26小寫字母。無論這個數多么大,他也不可能大過世界上可能存在的長地址。所以實現一一對應,本身就是不可能的。

    再換一個說法來反駁,如果真有這么一個算法和逆運算,那么基本上現在的壓縮軟件都可以歇菜了,而世界上所有的信息,都可以壓縮到100個字符。這~可能嗎。

    短 URL 系統是怎么設計的?

    另一個很爛的回答

    和上面一樣,也找一個算法,把長地址轉成短地址,但是不存在逆運算。我們需要把短對長的關系存到DB中,在通過短查長時,需要查DB。

    怎么說呢,沒有改變本質,如果真有這么一個算法,那必然是會出現碰撞的,也就是多個長地址轉成了同一個短地址。因為我們無法預知會輸入什么樣的長地址到這個系統中,所以不可能實現這樣一個絕對不碰撞的hash函數。

    比較爛的回答

    那我們用一個hash算法,我承認它會碰撞,碰撞后我再在后面加1,2,3不就行了。
    ok,這樣的話,當通過這個hash算法算出來之后,可能我們會需要做btree式的大于小于或者like查找到能知道現在應該在后面加1,2,或3,這個也可能由于輸入的長地址集的不確定性。導致生成短地址時間的不確定性。同樣爛的回答還有隨機生成一個短地址,去查找是否用過,用過就再隨機,如此往復,直到隨機到一個沒用過的短地址。

    正確的原理

    上面是幾種典型的錯誤回答,下面咱們直接說正確的原理。

    正確的原理就是通過發號策略,給每一個過來的長地址,發一個號即可,小型系統直接用mysql的自增索引就搞定了。如果是大型應用,可以考慮各種分布式key- value系統做發號器。不停的自增就行了。第一個使用這個服務的人得到的短地址是xx.xx/0 第二個是 xx.xx/1 第11個是 xx.xx/a 第依次往后,相當于實現了一個62進制的自增字段即可。

    幾個子問題

    1. 62進制如何用數據庫或者KV存儲來做?

    其實我們并不需要在存儲中用62進制,用10進制就好了。比如第10000個長地址,我們給它的短地址對應的編號是9999,我們通過存儲自增拿到9999后,再做一個10進制到62進制的轉換,轉成62進制數即可。這個10~62進制轉換,你完全都可以自己實現。

    2. 如何保證同一個長地址,每次轉出來都是一樣的短地址

    上面的發號原理中,是不判斷長地址是否已經轉過的。也就是說用拿著百度首頁地址來轉,我給一個xx.xx/abc 過一段時間你再來轉,我還會給你一個 xx.xx/xyz 。這看起來挺不好的,但是不好在哪里呢?不好在不是一一對應,而一長對多短。這與我們完美主義的基因不符合,那么除此以外還有什么不對的地方?

    有人說它浪費空間,這是對的。同一個長地址,產生多條短地址記錄,這明顯是浪費空間的。那么我們如何避免空間浪費,有人非常迅速的回答我,建立一個長對短的KV存儲即可。嗯,聽起來有理,但是。。。這個KV存儲本身就是浪費大量空間。所以我們是在用空間換空間,而且貌似是在用大空間換小空間。真的劃算嗎?這個問題要考慮一下。當然,也不是沒有辦法解決,我們做不到真正的一一對應,那么打個折扣是不是可以搞定?

    這個問題的答案太多種,各有各招。這個方案最簡單的是建立一個長對短的hashtable,這樣相當于用空間來換空間,同時換取一個設計上的優雅(真正的一對一)。實際情況是有很多性價比高的打折方案可以用,這個方案設計因人而異了。那我就說一下我的方案吧。
    我的方案是: 用key- value存儲,保存“最近”生成的長對短的一個對應關系。注意是“最近”,也就是說,我并不保存全量的長對短的關系,而只保存最近的。比如采用一小時過期的機制來實現LRU淘汰。
    這樣的話,長轉短的流程變成這樣:

    在這個“最近”表中查看一下,看長地址有沒有對應的短地址,有就直接返回,并且將這個key-value對的過期時間再延長成一小時如果沒有,就通過發號器生成一個短地址,并且將這個“最近”表中,過期時間為1小時所以當一個地址被頻繁使用,那么它會一直在這個key-value表中,總能返回當初生成那個短地址,不會出現重復的問題。如果它使用并不頻繁,那么長對短的key會過期,LRU機制自動就會淘汰掉它。當然,這不能保證100%的同一個長地址一定能轉出同一個短地址,比如你拿一個生僻的url,每間隔1小時來轉一次,你會得到不同的短地址。但是這真的有關系嗎?

    3.如何保證發號器的大并發高可用

    上面設計看起來有一個單點,那就是發號器。如果做成分布式的,那么多節點要保持同步加1,多點同時寫入,這個嘛,以CAP理論看,是不可能真正做到的。其實這個問題的解決非常簡單,我們可以退一步考慮,我們是否可以實現兩個發號器,一個發單號,一個發雙號,這樣就變單點為多點了?依次類推,我們可以實現1000個邏輯發號器,分別發尾號為0到999的號。每發一個號,每個發號器加1000,而不是加1。這些發號器獨立工作,互不干擾即可。而且在實現上,也可以先是邏輯的,真的壓力變大了,再拆分成獨立的物理機器單元。1000個節點,估計對人類來說應該夠用了。如果你真的還想更多,理論上也是可以的。(雪花算法的優化、美團發號算法的實現)

    4.具體存儲如何選擇

    這個問題就不展開說了,各有各道,主要考察一下對存儲的理解。對緩存原理的理解,和對市面上DB、Cache系統可用性,并發能力,一致性等方面的理解。

    5.跳轉用301還是302

    這也是一個有意思的話題。首先當然考察一個候選人對301和302的理解。瀏覽器緩存機制的理解。然后是考察他的業務經驗。301是永久重定向,302是臨時重定向。短地址一經生成就不會變化,所以用301是符合http語義的。同時對服務器壓力也會有一定減少。

    但是如果使用了301,我們就無法統計到短地址被點擊的次數了。而這個點擊次數是一個非常有意思的大數據分析數據源。能夠分析出的東西非常非常多。所以選擇302雖然會增加服務器壓力,但是我想是一個更好的選擇。

    總結

    以上是生活随笔為你收集整理的长URL链接转短链接算法的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。