短链生成方案初级入门
文章摘要
短链服务中,长链可对应多个短链,短链唯一对应长链。跳转采用302重定向以便统计点击和实时封禁。短链码通过MurmurHash算法生成并转为62进制,确保高性能、低碰撞和安全性。
**目录** [1.问题一:长链的关系和短链的关系是一对一还是一对多?](about:blank#1.%E9%97%AE%E9%A2%98%E4%B8%80%EF%BC%9A%E9%95%BF%E9%93%BE%E7%9A%84%E5%85%B3%E7%B3%BB%E5%92%8C%E7%9F%AD%E9%93%BE%E7%9A%84%E5%85%B3%E7%B3%BB%E6%98%AF%E4%B8%80%E5%AF%B9%E4%B8%80%E8%BF%98%E6%98%AF%E4%B8%80%E5%AF%B9%E5%A4%9A%EF%BC%9F) [2.问题二:前端访问短链是如何跳转到对应的页面的?](about:blank#2.%E9%97%AE%E9%A2%98%E4%BA%8C%EF%BC%9A%E5%89%8D%E7%AB%AF%E8%AE%BF%E9%97%AE%E7%9F%AD%E9%93%BE%E6%98%AF%E5%A6%82%E4%BD%95%E8%B7%B3%E8%BD%AC%E5%88%B0%E5%AF%B9%E5%BA%94%E7%9A%84%E9%A1%B5%E9%9D%A2%E7%9A%84%EF%BC%9F) [3.问题三:短链码如何是如何生成的](about:blank#3.%E9%97%AE%E9%A2%98%E4%B8%89%EF%BC%9A%E7%9F%AD%E9%93%BE%E7%A0%81%E5%A6%82%E4%BD%95%E6%98%AF%E5%A6%82%E4%BD%95%E7%94%9F%E6%88%90%E7%9A%84)   [为什么要用62进制转换,不是64进制?](about:blank#%C2%A0%C2%A0%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E7%94%A862%E8%BF%9B%E5%88%B6%E8%BD%AC%E6%8D%A2%2C%E4%B8%8D%E6%98%AF64%E8%BF%9B%E5%88%B6%EF%BC%9F) * * * 1.问题一:长链的关系和短链的关系是一对一还是一对多? ===========================         一个长链,在不同情况下(抖音推广、快手、短视频),**生成的短网址应该不一样**,才不会造成冲突,多渠道推广下,也可以**区分统计不同渠道的效果质量**     所以是 一个短链接只能对应一个长链接,当然一个长链接可以对应多个短链接(比如:一个长连接可对应抖音、朋友圈、快手的各个短链)。一短对一长,一长可以对应多个短。 2.问题二:前端访问短链是如何跳转到对应的页面的? =========================     一种是服务端转发 >     由服务器端进行的页面跳转,刚学Servlet时, 从OneServlet中转发到TwoServlet >     地址栏不发生变化,显示的是上一个页面的地址 >     请求次数:只有1次请求 >     转发只能在同一个应用的组件之间进行,不可以转发给其他应用的地址。所以在短链中不可用。     request.getRequestDispatcher("/two").forward(request, response);  ![](https://oss.120120.top/hiro/2023/02/10/3acc6170-829b-4155-8e5b-44fdfd148d31.jpeg)  还有一种是页面的跳转-重定向     由浏览器端进行的页面跳转 ![](https://oss.120120.top/hiro/2023/02/10/f5d391db-3e00-4405-9a9f-6d6c367294bd.jpeg)  重定向涉及到3xx状态码,访问跳转是301还是302,301和302代表啥意思?     301 是永久重定向 会被浏览器硬缓存,第一次会经过短链服务,后续再访问直接从浏览器缓存中获取目标地址     好处:短地址一经生成就不会变化,所以用 301 是同时对服务器压力也会有一定减少     坏处:但是如果**使用了 301,无法统计到短地址被点击的次数**     **302 是临时重定向 不会被浏览器硬缓存,每次都是会访问短链服务**     所以选择302虽然会增加服务器压力,但是有很多数据可以获取进行分析     **最后选择使用302**,这个也可以对违规推广的链接进行实时封禁 3.问题三:短链码如何是如何生成的 ================= 短链码需要有的特点:     1.生成性能强     2.碰撞概率低     3.避免重复     4.恶意猜测、业务规则安全 解决方式一:业界用的比较多的是自增ID ```java   利用插入数据库,利用数据库自增id     把自增id转成62进制作为短链码     短链码的长度不固定,随着 id 变大,短链码长度也增长     可以指定从某个长度开始增长,到百亿、千亿数量     转换工具:https://tool.lu/hexconvert/     是否存在重复: 不重复     但短链码是有序的递增,存在【业务数据安全】问题 ``` 解决方式二:MD5内容压缩 ```java 长链接做md5加密:比如加密成:43E08496,9E5CF455,E6D2D2B3,3407A6D2 加密串查询是否已经生成过短链接 如果已经存在,则拼接时间戳再MD5加密,插入数据库 如果不存在则把长链接、长链接加密串插入数据库 取MD5后 最后1 个 8 位字符串作为短链码 是否存在重复: 存在碰撞(重复)可能 是有损压缩算法,数据量超大情况碰撞概念越大 比如隔壁老王的女友有300多个,每再多1个,再同一天生日的概率越大,就更加复杂 ``` **解决方式三(建议使用的方式):** 哈希算法:将一个元素映射成另一个元素     加密哈希,如SHA256、MD5     非加密哈希,如MurMurHash,CRC32 本节采用MurMurHash > ``` > Murmur哈希是一种非加密散列函数,适用于一般的基于散列的查找。它在2008年由Austin Appleby创建,在Github上托管,名为“SMHasher” 的测试套件。 它也存在许多变种,所有这些变种都已经被公开。该名称来自两个基本操作,乘法(MU)和旋转(R)--来自百科 > ``` ```java 是一种【非加密型】哈希函数且【随机分布】特征表现更良好 由于是非加密的哈希函数,性能会比MD5强 再很多地方都用到比如Guava、Jedis、HBase、Lucence等 数据量 MurmurHash的 32 bit 能表示的最大值近 43 亿的10进制 满足多数业务,如果接近43亿则冲突概率大 MurMurHash得到的数值是10进制,一般会转化为62进制进行缩短 例子:10进制:1813342104 转62进制:1YIB7i 常规短链码是6~8位数字+大小写字母组合 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 6 位 62 进制数可表示 568 亿个短链(62的6次方,每位都有62个可能,如果扩大位数到7位,则可以支持3万5200亿) MurmurHash的 32 bit 满足多数业务 43亿 拼接上库-表位则可以表示更多数据(后续会涉及到分库分表的,库表位) 7位则可以到到 43亿 * 62 = 2666亿 8位则可以到到 2666亿 * 62 = 1.65万亿条数据 结合短链过期数据归档,理论上满足未来全部需求了 数据库存储 单表1千万 * 62个库 * 62表 = 384亿数据(可以满足当前业务需求) ```  使用Guava框里里面自带Murmur算法。先转成10进制。然后再转成62进制。 ![](https://oss.120120.top/hiro/2023/02/10/d35931ea-4789-4ee8-b0bb-457e1e0e1309.jpeg)  短链创建工具类封装以及使用方式 ```java @Slf4j public class CommonUtil { /** * murmurhash算法 * @param param * @return */ public static long murmurHash32(String param){ long murmurHash32 = Hashing.murmur3_32().hashUnencodedChars(param).padToLong(); return murmurHash32; } } import net.wnn.util.CommonUtil; import org.springframework.stereotype.Component; @Component public class ShortLinkComponent { /** * 62个字符 */ private static final String CHARS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; /** * 生成短链码 * @param param * @return */ public String createShortLinkCode(String param){ long murmurhash = CommonUtil.murmurHash32(param); //进制转换 String code = encodeToBase62(murmurhash); return code; } /** * 10进制转62进制 * @param num * @return */ private String encodeToBase62(long num){ // StringBuffer线程安全,StringBuilder线程不安全 StringBuffer sb = new StringBuffer(); do{ int i = (int )(num%62); sb.append(CHARS.charAt(i)); num = num/62; }while (num>0); String value = sb.reverse().toString(); return value; } } ``` 生成的短链码长度差不多。 ![](https://oss.120120.top/hiro/2023/02/10/4073375d-30d5-4005-b80f-c0a1d85e407a.jpeg)    为什么要用62进制转换,不是64进制? ------------------------    62进制转换是因为62进制转换后只含数字+小写+大写字母     而64进制转换会含有/、+这样的符号(不符合正常URL的字符)     10进制转62进制可以缩短字符,如果我们要6位字符的话,已经有560亿个组合了是可以支持业务需求的 具体的个数也是要看业务情况的,有些短链也会加入其它特殊字符 ![](https://oss.120120.top/hiro/2023/02/10/1905ce55-2e61-4433-8290-304edbc08165.jpeg) 本文转自 [https://blog.csdn.net/wnn654321/article/details/122022277](https://blog.csdn.net/wnn654321/article/details/122022277),如有侵权,请联系删除。
作者头像
admin
分享技术与生活
打赏作者

评论

暂无评论,快来抢沙发吧~