ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

设计简单高效的短链系统

2026/9/4 6:19:13 拓冰建站 浏览量
设计简单高效的短链系统

目录

 

引言

1. 短链系统的原理

1.1 长链接生成短码

1.2 短码映射到长链接

1.3 短码重定向

1.4 过期短 URL 清理

2. 设计与实现

2.1 数据存储

2.2 短码生成

2.3 接口设计

2.4 安全性考虑

2.5 访问性能优化


引言

        在当今数字化时代,人们对信息的分享需求不断增长,而长串复杂的URL链接却显得不够便捷和美观。为了解决这一问题,短链系统应运而生。本文将探讨设计一个简单高效的短链系统的原理与实现。

        例如在手机上会收到类似的信息,最后会被转到另外一个url,比如下面的链接会被定向到 https://page.xiaojukeji.com/active/ddpage_0IM6bugY.html?sojumpparam=gR2+gSMzQEIjGhpfDLdIwy2xcBkmZNG08Y36D09Ti90UwuMj1EccLugZQSvIuSVS&sampleId=t9dT0cXFt6O7JGe3BFOqDQ==&issueId=4124142163&origin=flicka&traceId=null

 链接上,并且这种链接有时效性,过一段时间会失效。

短链系统的简单执行流程 

 

1. 短链系统的原理

        短链系统的核心原理是通过将长URL映射到短的、容易记忆的字符串上,从而实现对原始链接的缩短。其基本流程如下:

1.1 长链接生成短码

        当用户输入或提交长URL时,系统首先会生成一个唯一的短码,可以是数字、字母组合,或者是更复杂的自定义规则。这一过程通常涉及到一种哈希算法,确保每个长链接对应一个唯一的短码。

1.2 短码映射到长链接

        生成短码后,系统需要建立一个映射关系,将短码与原始的长URL关联起来。这可以通过数据库或者缓存系统来实现,以便快速地检索和获取原链接。

1.3 短码重定向

        当用户访问短链接时,系统通过短码查找对应的原链接,并进行重定向,将用户引导至原始的长链接地址。

1.4 过期短 URL 清理

        过期短 URL 清理服务器定时启动一次,将已经超过有效期的 URL 数据删除。

2. 设计与实现

2.1 数据存储

        为了实现短码到长链接的映射,需要一个高效的数据存储系统。常见的选择包括关系型数据库(如MySQL)、NoSQL数据库(如Redis)或者分布式存储系统(如HDFS)。数据库的设计应考虑性能、可扩展性和数据一致性。

2.2 短码生成

        短码的生成可以使用基于哈希的算法,确保唯一性。另外,可以考虑使用自定义规则,比如将长码进行Base62编码,生成短码。

        将长 URL 利用 MD5 或者 SHA256 等单项散列算法,进行 Hash 计算,得到128bit 或者 256bit 的 Hash 值。然后对该 Hash 值进行 Base64 编码,得到 22个或者 43 个 Base64 字符,再截取前面的 6 个字符,就得到短 URL 了。

        但是这样得到的短 URL,可能会发生 Hash 冲突,即不同的长 URL,计算得到的短 URL 是相同的(MD5 或者 SHA256 计算得到的 Hash 值几乎不会冲突,但是 Base64 编码后再截断的 6 个字符有可能会冲突)。所以在生成的时候,需要先校验该短 URL 是否已经映射为其他的长 URL,如果是,那么需要重新计算。
我们的思路:
       1)将长网址md5生成32位签名串,分为4段, 每段8个字节;
       2)对这四段循环处理, 取8个字节, 将他看成16进制串与0x3fffffff(30位1)与操作, 即超过30位的忽略处理;
       3)这30位分成6段, 每5位的数字作为字母表的索引取得特定字符, 依次进行获得6位字符串;
       4)总的md5串可以获得4个6位串; 取里面的任意一个就可作为这个长url的短url地址;

 代码

 public static String[] shortUrl(String url) {// 对传入网址进行 MD5 加密String sMD5EncryptResult = DigestUtils.md5Hex(url);System.out.println("---------------sMD5EncryptResult: "+sMD5EncryptResult);System.out.println();//md5处理后是32位String hex = sMD5EncryptResult;//切割为4组,每组8个字符, 32 = 4 *  8String[] resUrl = new String[4];for (int i = 0; i < 4; i++) {//取出8位字符串,md5 32位,按照8位一组字符,被切割为4组String sTempSubString = hex.substring(i * 8, i * 8 + 8);System.out.println("---------------sTempSubString: "+sTempSubString);//System.out.println("-sTempSubString作为16进制的表示"+Long.parseLong(sTempSubString, 16));//把加密字符按照8位一组16进制与 0x3FFFFFFF 进行位与运算// 这里需要使用 long 型来转换,因为 Inteper .parseInt() 只能处理 31 位 , 首位为符号位 , 如果不用 long ,则会越界long lHexLong = 0x3FFFFFFF & Long.parseLong(sTempSubString, 16);System.out.println("---------lHexLong: "+lHexLong);String outChars = "";for (int j = 0; j < 6; j++) {//0x0000003D它的10进制是61,61代表最上面定义的chars数组长度62的0到61的坐标。//0x0000003D & lHexLong进行位与运算,就是格式化为6位,即保证了index绝对是61以内的值long index = 0x0000003D & lHexLong;System.out.println("----------index: "+index);// 按照下标index把从chars数组取得的字符逐个相加outChars += chars[(int) index];//每次循环按位移5位,因为30位的二进制,分6次循环,即每次右移5位lHexLong = lHexLong >> 5;}// 把字符串存入对应索引的输出数组,会产生一组6位字符串resUrl[i] = outChars;}return resUrl;}

2.3 接口设计

设计清晰简单的API接口,包括长链转短链、短链还原成长链等功能。使用RESTful风格可以使接口易于理解和使用。

我们需要两个接口

  • 一个是生成短链接接口

这个接口就是生成短链接,并存放在缓存数据库中。

  • 另一个是重定向到原始的URL

这个接口知识点是重定向,需http状态码的知识

  • 301:永久重定向,浏览器会缓存,自动重定向到新的地址
  • 302:临时重定向,客户端还是会继续使用旧的URL

整个跳转的流程:

  • 1.用户访问短链接,请求到达服务器
  • 2.服务器将短链接装换成为长链接,然后给浏览器返回重定向的状态码301/302
    • 301永久重定向会导致浏览器缓存重定向地址,短链接系统统计访问次数会不正确
    • 302临时重定向可以解决次数不准的问题,但是每次都会到短链接系统转换,服务器压力会变大。
  • 3.浏览器拿到重定向的状态码,以及真正需要访问的地址,重定向到真正的长链接上。

2.4 安全性考虑

        考虑到潜在的滥用和安全威胁,需要实施一些安全机制,例如限制短链接的有效期、监控访问频率等。

        比如如果我们使用redis来存储短链接,我们再放入redis中,同时设置好过期时间。如果使用mysql或者分布式存储HDFS来存储时,可以使用定时任务来清理过期的短链接。

2.5 访问性能优化

        通过合理的缓存机制和负载均衡,保证系统在高并发情况下依然能够快速响应用户请求。

        使用redis存储短链接的数据结构可以使用hash结构来存储短链接到长链接的映射。

        使用布隆过滤器可以防止被人疯狂请求一些不存在的短链接,导致数据库压力过大,甚至垮掉。

        另外在生成短链接时,我们可以使用预生成的短URL,预生成短 URL 的算法可以采用随机数来实现,6 个字符,每个字符都用随机数产生(用0~63 的随机数产生一个 Base64 编码字符)。为了避免随机数产生的短 URL 冲突,需要在预生成的时候检查该 URL 是否已经存在(用布隆过滤器检查)。因为预生成短URL是离线的,所以这时不会有性能方面的问题。并且预生成短 URL可以存储在文件系统中供我们使用。