1. 首页
  2. 后端

Java-如何设计短链

  Java-如何设计短链

===========

前言

短链,通俗地讲就是将原本非常长的URL链接精简,让短链接也能访问到原本的长链接。比如掘金给我们发送的系统通知。长链和短链让我们都能访问到同一篇文章。

image.png
长链:juejin.cn/post/738499…

短链:s.juejin.cn/ds/i6xxjfYC

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

  • 方便记忆,用户体验更好。短链简短,更加方便记忆,用户看到也更加舒适,想象一下要是掘金给你发个通知,文字没几个,一段下来全是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进制进一步缩短字符长度。

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

记录短链map

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

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='长链->短链表';

短链重定向

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

/**
 * 短链重定向
 */
@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. 使用布隆过滤器,将短链都放到布隆过滤器中,如果布隆中已经存在对应短链,就在长链中添加个随机字符串再次生成短链,如果还存在就再加个随机字符串,再次生成。
// 创建布隆过滤器
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

完整代码

前端(vue3):gitee.com/HT3902LY/wr…

后端(Java):gitee.com/HT3902LY/wr…

原文链接: https://juejin.cn/post/7388456632273223731

文章收集整理于网络,请勿商用,仅供个人学习使用,如有侵权,请联系作者删除,如若转载,请注明出处:http://www.cxyroad.com/17776.html

QR code