Java-如何设计短链

那既然有了长链,为什么还需要短链?

  • 方便记忆,用户体验更好。短链简短,更加方便记忆,用户看到也更加舒适,想象一下要是掘金给你发个通知,文字没几个,一段下来全是url地址,那用户看到是非常糟糕的。
  • 某些功能需要。某些功能发送的字数是有限制的,如果URL太长,那基本功能将无法满足,比如给用户发送短信时,供应商是有字数限制的;评论也是,URL占据过多,真正的内容表达就少了。
  • 方便后续统计追踪。当用户把文章分享出去,我们需要统计不同用户分享出去的点击量时,便可以在短链信息中带上用户ID。

核心讲解

原理

原理还是简单的,当用户访问短链时,我们给他返回302的状态,在header中带上Location,告诉浏览器这是一个临时文件,真正的文件需要访问Location中的地址。

image.png

请求流程

image.png

功能实现

长链->短链

那么长链又是转成短链的呢?后端接收到前端传过来的长链后,首先用hash算法将长链转成10进制的一组数,用md5或者sha都是可以的,只不过md5或者sha都是非对称加密,效率没有用hash高。这里我用的是hutoool工具的fnvHash,可以转成32位的10进制;之后再将10进制转成62进制进一步缩短字符长度。

 

java

复制代码

// 计算出长链的hash int fnvHash = HashUtil.fnvHash(longChain); // 10进制转62进制短链字符串 "1eDpPm" String shortChain = DecimalUtil.decimalTo62Base(fnvHash);

记录短链map

将长链对应短链map关系保存,可以保存到Redis,也可以保存到Mysql等数据库中。

 整理了这份面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题

需要全套面试笔记【点击此处】即可免费获取

sql

复制代码

CREATE TABLE `chain` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id', `long_chain` varchar(255) DEFAULT NULL COMMENT '长链', `short_chain` varchar(255) DEFAULT NULL COMMENT '短链', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='长链->短链表';

短链重定向

当前端发送访问短链请求时,先去找到短链对应长链,将重定向请求返回浏览器,浏览器再去请求长链。

 

java

复制代码

/** * 短链重定向 */ @GetMapping("/a/{shortChain}") public void query(@PathVariable String shortChain, HttpServletResponse response) { // 数据库查询对应长链 Chain chain = chainMapper.selectOne(new LambdaQueryWrapper<Chain>().eq(Chain::getShortChain, shortChain)); String longChain = chain.getLongChain(); //编码,防止url有中文 String encodeLongChain = URLUtil.encode(longChain); // 拼接域名、端口、访问文件前缀 String url = "http://localhost:19090/file/common"+encodeLongChain; //重定向 //response.sendRedirect(encodeUrl); response.setStatus(302); response.setHeader("location",url); }

特别注意

  • 在生成短链之前,我们需要检查一下这个长链是否已经转换过短链了,如果已经转换过了,就将Redis或者数据库中记录的短链返回。同时,如果是特别热点的数据,就像上面说的,掘金发给全部用户活动的短链,我们可以保存到Redis中,快速返回结果。
  • 🤔❓在长链用hash计算短链时,如果产生哈希冲突怎么办?哈希冲突产生就会出现不同长链对应相同的短链,虽然这个概率非常低。

解决方法:

  1. 将数据库中short_chain设置成不可重复。
  2. 使用布隆过滤器,将短链都放到布隆过滤器中,如果布隆中已经存在对应短链,就在长链中添加个随机字符串再次生成短链,如果还存在就再加个随机字符串,再次生成。
 

ini

复制代码

// 创建布隆过滤器 BitMapBloomFilter bitMap = BloomFilterUtil.createBitMap(10); String shortChain; while(true){ // 计算出长链的hash int fnvHash = HashUtil.fnvHash(longChain); // 10进制转62进制短链字符串 "1eDpPm" shortChain = DecimalUtil.decimalTo62Base(fnvHash); if(bitMap.contains(shortChain)){ longChain += RandomUtil.randomString(1); } else { bitMap.add(shortChain); break; } }

  • 🤔❓不同用户对于同一个长链怎么生成短链?

当需要统计同一篇文章不同人分享时的点击量,这时长链和短链的对应关系就是一对多了,在生成短链的时候就需要把用户的ID加到长链上了。

最终流程

AH5X89X}22QFU5GTYRUV%VQ.png

演示

GIF 2024-7-7 12-08-31.gif

  • 18
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值