中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么用Java設計一個短鏈接生成系統

發布時間:2021-12-11 15:47:49 來源:億速云 閱讀:388 作者:iii 欄目:開發技術

這篇文章主要講解了“怎么用Java設計一個短鏈接生成系統”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“怎么用Java設計一個短鏈接生成系統”吧!

引言

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

怎么用Java設計一個短鏈接生成系統

我們知道,短信有些是有字數限制的,直接放一個帶滿各種參數的鏈接,不合適,另外一點是,不想暴露參數。好處無非以下:

  • 太長的鏈接容易被限制長度

  • 短鏈接看著簡潔,長鏈接看著容易懵

  • 安全,不想暴露參數

  • 可以統一鏈接轉換,當然也可以實現統計點擊次數等操作

那背后的原理是什么呢?怎么實現的?讓你實現這樣的系統,你會怎么設計呢?【來自于某鵝場面試官】

短鏈接的原理

短鏈接展示的邏輯

這里最重要的知識點是重定向,先復習一下http的狀態碼:

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

那么以 3 開頭的狀態碼都是關于重定向的:

  • 300:多種選擇,可以在多個位置存在

  • 301:永久重定向,瀏覽器會緩存,自動重定向到新的地址

  • 302:臨時重定向,客戶端還是會繼續使用舊的URL

  • 303:查看其他的地址,類似于301

  • 304:未修改。所請求的資源未修改,服務器返回此狀態碼時,不會返回任何資源。

  • 305:需要使用代理才能訪問到資源

  • 306:廢棄的狀態碼

  • 307:臨時重定向,使用Get請求重定向

整個跳轉的流程:

1.用戶訪問短鏈接,請求到達服務器

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

301永久重定向會導致瀏覽器緩存重定向地址,短鏈接系統統計訪問次數會不正確

302臨時重定向可以解決次數不準的問題,但是每次都會到短鏈接系統轉換,服務器壓力會變大。

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

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

怎么用Java設計一個短鏈接生成系統

短鏈接怎么設計的

全局發號器

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

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

實際也很簡單,就是數據庫里面的一條數據,一個id對應長鏈接(相當于全局的發號器,全局唯一的ID):

idurl
1gd.10086.cn/gmccapp/web…

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

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

id 轉換策略

但是直接用遞增的數字,有兩個壞處:

  • 數字很大的時候,還是很長

  • 遞增的數字,不安全,規律性太強了

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

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轉 62位的key 或者key裝換成為id都已經實現了,不過計算還是比較耗時的,不如加個字段存起來,于是數據庫變成了:

idkeyurl
27095455234tzHLFwgd.10086.cn/gmccapp/web…

但是這樣還是很容易被猜出這個id和key的對應關系,要是被遍歷訪問,那還是很不安全的,如果擔心,可以隨機將短鏈接的字符順序打亂,或者在適當的位置加上一些隨機生成的字符,比如第1,4,5 位是隨機字符,其他位置不變,只要我們計算的時候,將它對應的關系存到數據庫,我們就可以通過連接的key找到對應的url。(值得注意的是,key必須是全局唯一的,如果沖突,必須重新生成)

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

怎么用Java設計一個短鏈接生成系統

性能考慮

如果有很多短鏈接暴露出去了,數據庫里面數據很多,這個時候可以考慮使用緩存優化,生成的時候順便把緩存寫入,然后讀取的時候,走緩存即可,因為一般短鏈接和長鏈接的關系不會修改,即使修改,也是很低頻的事情。

如果系統的id用完了怎么辦?這種概率很小,如果真的發生,可以重用舊的已經失效的id號。

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

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

感謝各位的閱讀,以上就是“怎么用Java設計一個短鏈接生成系統”的內容了,經過本文的學習后,相信大家對怎么用Java設計一個短鏈接生成系統這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

莎车县| 康马县| 广丰县| 蒙阴县| 孝昌县| 宁乡县| 日照市| 宁城县| 海淀区| 达日县| 宁明县| 寻甸| 咸阳市| 沁阳市| 光泽县| 博野县| 安康市| 黑龙江省| 邢台市| 舞钢市| 西乡县| 苏州市| 龙州县| 瑞丽市| 英吉沙县| 修武县| 嘉鱼县| 荆门市| 铜鼓县| 社旗县| 郎溪县| 靖州| 博白县| 昌乐县| 全南县| 焉耆| 维西| 中江县| 临安市| 德令哈市| 延津县|