如何实现 长链接变 短 链接?

article/2025/10/9 21:01:09

短链接,通俗来说,就是将长的 URL 网址,通过程序计算等方式,转换为简短的网址字符串。

大家经常会收到一些莫名的营销短信,里面有一个非常短的链接让你跳转。新浪微博因为限制字数,所以也会经常见到这种看着不像网址的网址。短链的兴起应该就是微博限制字数激起了大家的创造力。

如果创建一个短链系统,我们应该做什么呢?

  1. 将长链接变为短链;

  2. 用户访问短链接,会跳转到正确的长链接上去。

查找到对应的长网址,并跳转到对应的页面。

短链生成方法

短码一般是由[a - z, A - Z, 0 - 9]这 62 个字母或数字组成,短码的长度也可以自定义,但一般不超过 8 位。比较常用的都是 6 位,6 位的短码已经能有 568 亿种的组合:(26+26+10)^6 = 56800235584,已满足绝大多数的使用场景。

目前比较流行的生成短码方法有:自增id摘要算法普通随机数。分布式ID生成器的解决方案总结,这篇也参考看下。

自增 id

该方法是一种无碰撞的方法,原理是,每新增一个短码,就在上次添加的短码 id 基础上加 1,然后将这个 10 进制的 id 值,转化成一个 62 进制的字符串。

一般利用数据表中的自增 id 来完成:每次先查询数据表中的自增 id 最大值 max,那么需要插入的长网址对应自增 id 值就是 max+1,将 max+1 转成 62 进制即可得到短码。

但是短码 id 是从一位长度开始递增,短码的长度不固定,不过可以用 id 从指定的数字开始递增的方式来处理,确保所有的短码长度都一致。同时,生成的短码是有序的,可能会有安全的问题,可以将生成的短码 id,结合长网址等其他关键字,进行 md5 运算生成最后的短码。

摘要算法

摘要算法又称哈希算法,它表示输入任意长度的数据,输出固定长度的数据。相同的输入数据始终得到相同的输出,不同的输入数据尽量得到不同的输出。

算法过程:

  1. 将长网址 md5 生成 32 位签名串,分为 4 段, 每段 8 个字节;

  2. 对这四段循环处理, 取 8 个字节, 将他看成 16 进制串与 0x3fffffff(30 位 1)与操作, 即超过 30 位的忽略处理;

  3. 这 30 位分成 6 段, 每 5 位的数字作为字母表的索引取得特定字符, 依次进行获得 6 位字符串;

  4. 总的 md5 串可以获得 4 个 6 位串;取里面的任意一个就可作为这个长 url 的短 url 地址;

这种算法,虽然会生成 4 个,但是仍然存在重复几率。

虽然几率很小,但是该方法依然存在碰撞的可能性,解决冲突会比较麻烦。不过该方法生成的短码位数是固定的,也不存在连续生成的短码有序的情况。

普通随机数

该方法是从 62 个字符串中随机取出一个 6 位短码的组合,然后去数据库中查询该短码是否已存在。如果已存在,就继续循环该方法重新获取短码,否则就直接返回。

该方法是最简单的一种实现,不过由于Math.round()方法生成的随机数属于伪随机数,碰撞的可能性也不小。在数据比较多的情况下,可能会循环很多次,才能生成一个不冲突的短码。

算法分析

以上算法利弊我们一个一个来分析。

如果使用自增 id 算法,会有一个问题就是不法分子是可以穷举你的短链地址的。原理就是将 10 进制数字转为 62 进制,那么别人也可以使用相同的方式遍历你的短链获取对应的原始链接。

打个比方说:http://tinyurl.com/a3300和 http://bit.ly/a3300,这两个短链网站,分别从a3300 - a3399,能够试出来多次返回正确的 url。所以这种方式生成的短链对于使用者来说其实是不安全的。

摘要算法,其实就是 hash 算法吧,一说 hash 大家可能觉得很 low,但是事实上 hash 可能是最优解。比如:http://www.sina.lt/ 和 http://mrw.so/ 连续生成的 url 发现并没有规律,很有可能就是使用 hash 算法来实现。

普通随机数算法,这种算法生成的东西和摘要算法一样,但是碰撞的概率会大一些。因为摘要算法毕竟是对 url 进行 hash 生成,随机数算法就是简单的随机生成,数量一旦上来必然会导致重复。

综合以上,我选择最 low 的算法:摘要算法。

实现
存储方案

数据库存储方案

短网址基础数据采用域名和后缀分开存储的形式。另外域名需要区分 HTTP 和 HTTPS,hash 方案针对整个链接进行 hash 而不是除了域名外的链接。域名单独保存可以用于分析当前域名下链接的使用情况。

增加当前链接有效期字段,一般有短链需求的可能是相关活动或者热点事件,这种短链在一段时间内会很活跃,过了一定时间热潮会持续衰退。所以没有必要将这种链接永久保存增加每次查询的负担。

对于过期数据的处理,可以在新增短链的时候判断当前短链的失效日期,将每天到达失效日期的数据在 HBase 单独建一张表,有新增的时候判断失效日期放到对应的 HBase 表中即可,每天只用处理当天 HBase 表中的失效数据。

数据库基础表如下:

base_urlsuffix_urlshot_codetotal_click_countfull_urlexpiration_date

http://www.aichacha.com

/search/12345

edfg3s


http://www.aichacha.com//search/12345


http://www.aichacha.com

/aiCheck/getResult/123

Fe9dq


http://www.aichacha.com//aiCheck/getResult/123


http://www.baidu.com

/wenku/12354

lcfr53


http://www.baidu.com/wenku/12354


字段释义:

base_url:域名

suffix_url:链接除了域名外的后缀

full_url:完整链接

shot_code:当前 suffix_url 链接的短码

expiration_date:失效日期

total_click_count:当前链接总点击次数

expiration_date:当前链接失效时间

缓存方案

  • 查询需求

个人认为对于几百个 G 的数据量都放在缓存肯定是不合适的,所以有个折中的方案:将最近 3 个月内有查询或者有新增的 url 放入缓存,使用 LRU 算法进行热更新。这样最近有使用的发概率会命中缓存,就不用走库。查不到的时候再走库更新缓存。

  • 新增需求

对于新增的链接就先查缓存是否存在,缓存不存在再查库,数据库已经分表了,查询的效率也不会很低。

  • 缓存的设计

查询的需求是用户拿着短链查询对应的真实地址,那么缓存的 key 只能是短链,可以使用 KV 的形式存储。


番外

其实也可以考虑别的存储方案,比如 HBase,HBase 作为 NOSQL 数据库,性能上仅次于 redis 但是存储成本比 redis 低很多个数量级,存储基于 HDFS,写数据的时候会先先写入内存中,只有内存满了会将数据刷入到 HFile。

关注微信公众号:Java技术栈,在后台回复:redis,可以获取我整理的 N 篇最新Redis教程,都是干货。

读数据也会快,原因是因为它使用了 LSM 树型结构,而不是 B 或 B+树。HBase 会将最近读取的数据使用 LRU 算法放入缓存中,如果想增强读能力,可以调大 blockCache。

其次,也可以使用 ElasticSearch,合适的索引规则效果不输缓存方案。


是否有分库分表的需要?

对于单条数据 10b 以内,一亿条数据总容量大约为 953G,单表肯定无法撑住这么大的量,所以有分表的需要,如果你对服务很有信心 2 年内能达到这个规模,那么你可以从一开始设计就考虑分表的方案。推荐:大厂在用的分库分表方案,看这篇就够了。

那么如何定义分表的规则呢?

如果按照单表 500 万条记录来算,总计可以分为 20 张表,那么单表容量就是 47G,还是挺大,所以考虑分表的 key 和单表容量,如果分为 100 张表那么单表容量就是 10G,并且通过数字后缀路由到表中也比较容易。可以对 short_code 做 encoding 编码生成数字类型然后做路由。

如何转跳

当我们在浏览器里输入 http://bit.ly/a3300 时

  1. DNS 首先解析获得 http://bit.ly的IP地址

  2. DNS获得IP地址以后(比如:12.34.5.32),会向这个地址发送HTTPGET请求,查询短码a3300

  3. [http://bit.ly 服务器会通过短码a3300获取对应的长 URL

  4. 请求通过HTTP301转到对应的长 URL http://www.theaustralian.news.com.au/story/0,25197,26089617-5013871,00.html。

这里有个小的知识点,为什么要用 301 跳转而不是 302 呐?

知识点:为什么要使用 302 跳转,而不是 301 跳转呢?

301 是永久重定向,302 是临时重定向。短地址一经生成就不会变化,所以用 301 是符合 http 语义的。但是如果用了 301, Google,百度等搜索引擎,搜索的时候会直接展示真实地址,那我们就无法统计到短地址被点击的次数了,也无法收集用户的 Cookie, User Agent 等信息,这些信息可以用来做很多有意思的大数据分析,也是短网址服务商的主要盈利来源。

引自知乎-武林的回:https://www.zhihu.com/question/20103344/answer/573638467

附上两个算法:

摘要算法:


import org.apache.commons.lang3.StringUtils;import javax.xml.bind.DatatypeConverter;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.atomic.AtomicLong;import static com.alibaba.fastjson.util.IOUtils.DIGITS;/*** @author rickiyang* @date 2020-01-07* @Desc TODO*/
public class ShortUrlGenerator {public static void main(String[] args) {String sLongUrl = "http://www.baidu.com/121244/ddd";for (String shortUrl : shortUrl(sLongUrl)) {System.out.println(shortUrl);}}public static String[] shortUrl(String url) {// 可以自定义生成 MD5 加密字符传前的混合 KEYString key = "dwz";// 要使用生成 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 = "";try {MessageDigest md = MessageDigest.getInstance("MD5");md.update((key + url).getBytes());byte[] digest = md.digest();sMD5EncryptResult = DatatypeConverter.printHexBinary(digest).toUpperCase();} catch (NoSuchAlgorithmException e) {e.printStackTrace();}String[] resUrl = new String[4];//得到 4组短链接字符串for (int i = 0; i < 4; i++) {// 把加密字符按照 8 位一组 16 进制与 0x3FFFFFFF 进行位与运算String sTempSubString = sMD5EncryptResult.substring(i * 8, i * 8 + 8);// 这里需要使用 long 型来转换,因为 Inteper .parseInt() 只能处理 31 位 , 首位为符号位 , 如果不用 long ,则会越界long lHexLong = 0x3FFFFFFF & Long.parseLong(sTempSubString, 16);String outChars = "";//循环获得每组6位的字符串for (int j = 0; j < 6; j++) {// 把得到的值与 0x0000003D 进行位与运算,取得字符数组 chars 索引(具体需要看chars数组的长度   以防下标溢出,注意起点为0)long index = 0x0000003D & lHexLong;// 把取得的字符相加outChars += chars[(int) index];// 每次循环按位右移 5 位lHexLong = lHexLong >> 5;}// 把字符串存入对应索引的输出数组resUrl[i] = outChars;}return resUrl;}}

数字转为 base62 算法:


/*** @author rickiyang* @date 2020-01-07* @Desc TODO* <p>* 进制转换工具,最大支持十进制和62进制的转换* 1、将十进制的数字转换为指定进制的字符串;* 2、将其它进制的数字(字符串形式)转换为十进制的数字*/
public class NumericConvertUtils {public static void main(String[] args) {String str = toOtherNumberSystem(22, 62);System.out.println(str);}/*** 在进制表示中的字符集合,0-Z分别用于表示最大为62进制的符号表示*/private static final char[] digits = {'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'};/*** 将十进制的数字转换为指定进制的字符串** @param number 十进制的数字* @param seed   指定的进制* @return 指定进制的字符串*/public static String toOtherNumberSystem(long number, int seed) {if (number < 0) {number = ((long) 2 * 0x7fffffff) + number + 2;}char[] buf = new char[32];int charPos = 32;while ((number / seed) > 0) {buf[--charPos] = digits[(int) (number % seed)];number /= seed;}buf[--charPos] = digits[(int) (number % seed)];return new String(buf, charPos, (32 - charPos));}/*** 将其它进制的数字(字符串形式)转换为十进制的数字** @param number 其它进制的数字(字符串形式)* @param seed   指定的进制,也就是参数str的原始进制* @return 十进制的数字*/public static long toDecimalNumber(String number, int seed) {char[] charBuf = number.toCharArray();if (seed == 10) {return Long.parseLong(number);}long result = 0, base = 1;for (int i = charBuf.length - 1; i >= 0; i--) {int index = 0;for (int j = 0, length = digits.length; j < length; j++) {//找到对应字符的下标,对应的下标才是具体的数值if (digits[j] == charBuf[i]) {index = j;}}result += index * base;base *= seed;}return result;}
}

作者: rickiyang

www.cnblogs.com/rickiyang/p/12178644.html

END

学习资料:

分享一份最新 Java 架构师学习资料

最近热文:

1、用户密码到底要怎么加密存储?

2、为什么 Redis 默认 16 个库?

3、阿里面试 Java 都问什么?万字总结!

4、京东把 Elasticsearch 用的真牛逼!

5、IDEA 公司推出新字体,极度舒适~

Java干货:

1、2020 最新 Java 面试题整理,建议收藏!

2、Oracle JDK 和 OpenJDK 有什么区别?

3、Java 14 令人期待的 5 大新特性!

4、Java中的对象都是在堆上分配的吗?

5、图文并茂,傻瓜都能看懂的JVM内存布局

Spring干货:

1、Spring 事务失效的 8 大原因,吊打面试官!

2、Spring 面试 7 大问题,你顶得住不?

3、Spring Boot 之配置导入,强大到不行!

4、Spring Cloud Greenwich最后计划版本发布!

5、Spring Cloud 升级最新 Greenwich 版本

本公众号干货实在太多了,没法都搬上来,扫码关注Java技术栈公众号,获取更多最主流的 Java 技术干货。

点击「阅读原文」带你飞~


http://chatgpt.dhexx.cn/article/OxpoTKCo.shtml

相关文章

微信:长链接转短链接

前言 微信复制出来的链接太长&#xff0c;想转短连接如何做&#xff1f; 将一条长链接转成短链接。 主要使用场景&#xff1a; 开发者用于生成二维码的原链接&#xff08;商品、支付二维码等&#xff09;太长导致扫码速度和成功率下降&#xff0c;将原长链接通过此接口转成短…

长链接 转换成 短链接

文章目录 参考来源思路方法一方法二 参考来源 豆瓣 短链接生成的算法原理 思路 方法一 一般会想到用哈希&#xff0c;这里可以用MD5码获取哈希值&#xff0c;但时MD5生成的串挺长的&#xff0c;这类要考虑怎么把它变短。 做法如下&#xff1a; 方法二 很好想的思路&…

长链接 转短链接URL的设计思路

最烂的回答 实现一个算法&#xff0c;将长地址转成短地址。实现长和短一一对应。然后再实现它的逆运算&#xff0c;将短地址还能换算回长地址。 这个回答看起来挺完美的&#xff0c;然后候选人也会说现在时间比较短&#xff0c;如果给我时间我去找这个算法就解决问题了。但是稍…

长链接转成短链接的原理和实现详解

一、为什么要设计短链接&#xff0c;短链接有什么好处&#xff1f; 1、链接变短&#xff0c;在对内容长度有限制的平台发文&#xff0c;可编辑的文字就变多了。 比如&#xff1a;微博&#xff0c;限定了只能发 140 个字&#xff0c;如果一串长链直接怼上去&#xff0c;其他可…

长链到短链转化

文章目录 1:为什么将长链转化为短链&#xff1f;2:短链跳转的基本原理3&#xff1a;将长链转化为短链&#xff08;Hash&#xff09;3.1:hash3.1.1:hash算法的选取3.1.2hash后还是有点长3.1.3:解决hash冲突 3.2:自增序列算法 1:为什么将长链转化为短链&#xff1f; 1、链接变短…

2022年最新Python学习路线图(内附视频资料)【六张图带你掌握Python技巧】

目录 一、基础语法学习 二、制定发展方向 三、编程实践 四、资料获取 五、学习路线图​ 一、基础语法学习 Python的基础语法包括两大部分&#xff0c;其一是函数式编程部分&#xff0c;其二是面向对象编程部分。函数式部分的内容还是比较简单的&#xff0c;包括列表、函数…

零基础Python学习路线图,小白的进阶之路!

近几年Python的受欢迎程度可谓是扶摇直上&#xff0c;当然了学习的人也是愈来愈多。一些学习Python的小白在学习初期&#xff0c;总希望能够得到一份Python学习路线图&#xff0c;小编经过多方汇总为大家汇总了一份Python学习路线图。 对于一个零基础的想学习python的朋友来说…

15张超详细的Python学习路线图,纯良心分享,零基础学习宝典

这是一篇 Python 入门指南&#xff0c;针对那些没有任何编程经验&#xff0c;从零开始学习 Python 的同学。不管你学习的出发点是兴趣驱动、拓展思维&#xff0c;还是工作需要、想要转行&#xff0c;都可以用此文作为一个参考。 在这个信息爆炸的时代&#xff0c;以 “Python入…

2020最新版Python学习路线图

Python学习路线图网上有很多版本&#xff0c;前川网的这套Python学习路线图是2020最新版的&#xff0c;是根据企业招聘的要求不断更新的学习路线图&#xff0c;对之前的Pyhton学习路线图做了一些调整和改变&#xff0c;想要用Python爬虫或者深度学习人工智能的看这套Python学习…

Python 学习之路

最近在疫情静默管理期间&#xff0c;刚好有时间可以学习一下Python&#xff0c;非常幸运&#xff0c;找到一本Eric Matthes的《Python Crash Course》Python编程从入门到实践&#xff0c;好好研究一下。基础的语法就是一带而过了&#xff0c;使用的Python3.8.10版本&#xff0c…

一文讲清Python的7大学习路线(建议收藏)

现如今铺天盖地都是来自学习Python的勇士&#xff0c;Python这个编程语言中最友好的语言早已不是高不可攀的状态了。 无论是业余爱好&#xff0c;还是专职求学&#xff0c;学习Python的朋友都在依靠着自己的方法&#xff0c;勤勤恳恳的学习着&#xff0c;但是学习有方向&#x…

超全的Python学习路线图

Python是一种编程语言 完成同一个任务&#xff0c;C语言要写1000行代码&#xff0c;Java只需要写100行&#xff0c;而Python可能只要20行。用Python完成项目&#xff0c;编写的代码量更少&#xff0c;代码简短可读性强&#xff0c;团队协作开发时读别人的代码速度会非常快&…

零基础Python学习路线图

Python学习路线图先奉上&#xff1a; Python教程_完全入门 推荐视频&#xff1a;https://www.bilibili.com/video/BV1jZ4y1p7zQ Python学习路线 第一阶段Python基础与Linux数据库 掌握Python基本语法规则及变量、逻辑控制、内置数据结构、文件操作、高级函数、模块、常用标…

Python学习路线图(2021最新版)

这是我最开始学Python时的一套学习路线&#xff0c;从入门到上手。&#xff08;不敢说精通&#xff0c;哈哈~&#xff09; 一、Python基础知识、变量、数据类型 二、Python条件结构、循环结构 三、Python函数 四、字符串 五、列表与元组 六、字典与集合 最后再送给大家一套免费…

python学习路线-思维导图

文章目录 1. python学习大纲2. python基础大纲2.1 python语言基础2.2 标准数据类型12.3 标准类型补充2.4 标准数据类型22.5 标准数据类型32.6 条件&循环2.7 计算机基础 3. python进阶大纲3.1 进阶条件&循环3.2 函数&模块3.3 面向对象3.4 补充知识3.5 文件对象3.6 异…

熬夜怒肝,保姆级Python学习路线,起飞!

想当初女朋友编程小白零基础&#xff0c;到如今在互联网大厂做算法工作&#xff0c;就是我带她漂进Python的海洋&#xff0c;从此一去不复返~ 我给她制订的学习路线十分适合萌新&#xff0c;总共分三步&#xff1a; 看视频 作项目 啃厚书 看视频 如果是零基础&#xff0c…

正确的Python学习路线图,来了!

国庆长假余额还剩最后一天啦&#xff0c;这两天陆续有很多新的同学加我微信&#xff0c;咨询问题。想学Python&#xff0c;但是Python的图书太多太多了&#xff0c;很容易从入门到放弃&#xff0c;咨询菜鸟哥能否推荐一些图书&#xff0c;然后由浅入深的阅读。今天我们就来说一…

Python学习路线

谈到学习路线&#xff0c;入门是基础课。基本上&#xff0c;熟练掌握Python入门指南即可。 其次&#xff0c;要想更进一步&#xff0c;需要熟读官方文档&#xff0c;掌握各种内置函数、标准库等知识。关于两者&#xff0c;英文不好的鱼油们可以关Python中文官方文档板块&#x…

2022新版Python所有方向的学习路线图,自学少走弯路秘籍

最近花了不少时间专门去更新了一下Python所有方向的学习路线图&#xff0c;在之前的基础上做很多的改良&#xff0c;希望能够帮助自学的小伙伴们&#xff0c;多一份参考&#xff0c;避免少走弯路。 但首先我得先说明一下&#xff0c;每个技术人对技术的看法都不尽相同&#xf…

史上最详细python学习路线-从入门到精通,只需5个月时间

针对Python的初学者&#xff0c;从无到有的Python语言如何入门&#xff0c;主要包括了&#xff1a;Python的简介&#xff0c;如何下载Python&#xff0c;如何安装Python&#xff0c;如何使用终端、Shell&#xff0c;IDE等各种开发环境进行Python开发&#xff0c;Python中的语法…