前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java-如何设计短链

Java-如何设计短链

原创
作者头像
BLACK595
发布2024-09-19 09:47:24
1090
发布2024-09-19 09:47:24

前言

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

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

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

核心讲解

原理

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

请求流程

功能实现

长链->短链

那么长链又是转成短链的呢?后端接收到前端传过来的长链后,首先用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等数据库中。

代码语言: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设置成不可重复。// 创建布隆过滤器 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; } }
  2. 使用布隆过滤器,将短链都放到布隆过滤器中,如果布隆中已经存在对应短链,就在长链中添加个随机字符串再次生成短链,如果还存在就再加个随机字符串,再次生成。
  • 🤔❓不同用户对于同一个长链怎么生成短链?

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

最终流程

演示

完整代码

前端(vue3):https://gitee.com/HT3902LY/writing_front

后端(Java):https://gitee.com/HT3902LY/writing_back

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 那既然有了长链,为什么还需要短链?
  • 核心讲解
    • 原理
      • 请求流程
      • 功能实现
        • 长链->短链
          • 记录短链map
            • 短链重定向
            • 特别注意
            • 最终流程
              • 演示
              • 完整代码
              相关产品与服务
              云数据库 Redis®
              腾讯云数据库 Redis®(TencentDB for Redis®)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档