2025年短网址的设计与实现

短网址的设计与实现短网址 顾名思义 短网址就是一个很短的链接而已 在生活中我们经常能收到诸如以下短信 若我们点开此链接会发现实际的 URL 十分长 https fast wallet finzjr com file marketing 20210624 f1739910 5531 4380 b33b d8dc94d294b1 html fy 1 amp

大家好,我是讯享网,很高兴认识大家。

短网址

      顾名思义,短网址就是一个很短的链接而已。在生活中我们经常能收到诸如以下短信。
请输入图片描述
讯享网

      若我们点开此链接会发现实际的URL十分长。

https://fast-wallet.finzjr.com/file/marketing/20210624/f1739910-5531-4380-b33b-d8dc94d294b1.html?fy=1&from=701&e_channel=duanxin_new_dianshang_0801

讯享网

      似乎这只是做了一个转换呀!有什么高级的呢?长链不行吗?这是怎么做到的?这是我初次遇见短链时抛出的种种问题,相信大家也会由此困惑。接下来将一一解答。

代码仓库:https://gitee.com/catwings/long-shorturl

短链的优势

  • 短信发送是有字数限制的,若发送长链可能连广告内容都没处写了;
  • 短链在内容上对用户友好,不会像长链一样一堆字符;
  • 链接太长在有些平台上无法自动识别为超链接,只能用短链

短链的基本原理

      通过简单的浏览器抓包我们可以很快速的了解短链跳转的基本原理:
请输入图片描述

      可以看到请求短链后,返回了状态码 301(重定向)与 location 值为长链的响应,然后浏览器会再请求这个长链以得到最终的响应,整个交互流程图如下:
请输入图片描述

不难猜出在短网址系统中肯定做了短链与长链的对应,查询出对应长链后直接重定向。

短链的生成

      短链是由固定短链域名 + 长链映射成的一串字母组成的,生成的那一串字母就是整个短网址系统的核心所在,如何将长链转换为一小段字符是首要考虑的任务。

Hash?

      上述提到短网址系统中做了短链与长链的映射,提起映射大家首先想到的就是Hash了,将长链使用相应的Hash算法生成对应的HashCode,可以以此为短链。

很遗憾,基于Hash的生成会导致哈希冲突,对大流量的网站不合适。而我们无法难以设计一个没有哈希冲突的算法

随机再去重?

      除了使用Hash算法这一高大上的方式,我们可以随机生成一个6为的短链,首先去数据库中查询是否存在,若存在则重新生成,否则直接使用。
请输入图片描述

      代码实现如下所示:

讯享网private String longToShort(String longUrl){ while(true){ String shortUrl = UUID.randomUUID().toString().replaceAll("-",""); UrlEntity urlEntity = urlMapper.selectByShortUrl(shortUrl); if(urlEntity != null){ // 有重复 continue; } // 没重复,直接插入 urlMapper.insertShortUrl(shortUrl,longUrl); } } 

      数据表如下所示:

+----+-----------+----------------------------+ | id | short_url | long_url | +----+-----------+----------------------------+ | 1 | feafea + http://www.chengpengper.cn | | 2 | sfevef + http://www.chengpengper.cn | | 3 | zdfesa + http://www.chengpengper.cn | | 4 | csedaq + http://www.chengpengper.cn | | 5 | cesade + http://www.chengpengper.cn | | 6 | jkonlo + http://www.codelife.cn | | 7 | podexe + http://www.codelife.cn | +----+-----------+----------------------------+ 

随机再去重的方案实现简单,但是其生成短网址的速度会随着数据量的增加而变得越来越慢

62进制

      为什么是62进制?那是因为0-9、a-z、A-Z共62个字符。
      我们将一个6位的shortUrl看做一个62进制数,如’feafea’对应的十进制为。若我们能生成一个唯一的十进制数,自然可以将其转换为62进制数。在单体系统中我们可以借助MySql的自增主键完成唯一ID的生成,再将其转换为62进制的6位短链,而通过短链查询长链只需要将62进制转为十进制(即ID),根据ID查询即可。
请输入图片描述

如上图生成短链中我们没有去判断数据库中是否已经有此长链了,而是无脑的insert,可以在插入前根据长链查找是否已经存在了,存在则直接返回,否则执行后续逻辑

      进制转换核心代码如下所示:

讯享网public class UrlUtils { static final String str = "0abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; static final int MAX_LEN = 6; / * 进制转换 Base62 */ / * id 转 shortUrl * @param shortUrl 短网址 * @return 短网址对应的 id */ public static long shortUrlToId(String shortUrl){ long id = 0; char[] chars = shortUrl.toCharArray(); for(int i=0;i < chars.length; i++){ id = id * 62 + toBase62(chars[i]); } return id; } private static int toBase62(char ch){ return str.indexOf(ch); } / * id 转 短网址 * @param id id * @return id 对应的短网址 */ public static String idToShortUrl(Long id){ StringBuilder shortUrl = new StringBuilder(); while ( id > 0){ shortUrl.append(str.charAt((int)(id % 62))); id /= 62; } while(shortUrl.length() < MAX_LEN){ shortUrl.append("0"); } return shortUrl.reverse().toString(); } } 
重定向

      重定向跳转的核心方法如下所示:

@GetMapping("/{shortUrl}") public String shortTolongUrl(@PathVariable String shortUrl, HttpServletResponse response){ String longUrl = urlService.shortTolong(shortUrl); response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);//301 response.setHeader("Location", longUrl); response.setHeader("Connection", "close"); return "redirect:"+longUrl; } 
数据库变化

      和随机生成再去重中的数据表不同,我们不需要再保存具体的短网址字符串了。

讯享网+----+----------------------------+ | id | long_url | +----+----------------------------+ | 1 | http://www.chengpengper.cn | | 2 | http://www.chengpengper.cn | | 3 | http://www.chengpengper.cn | | 4 | http://www.chengpengper.cn | | 5 | http://www.chengpengper.cn | | 6 | http://www.codelife.cn | | 7 | http://www.codelife.cn | +----+----------------------------+ 

为什么是6位的长度呢?这就需要看6位的62进制数能表示多少URL了(估算):

  • 5位 = 62^5 = 9亿
  • 6位 = 62^6 = 570亿
  • 7位 = 62^7 = 35000亿

所以,6位的62进制足够我们使用了。

自定义短链

      有些时候用户不希望系统自动生成短链,而是希望自定义短链。

新建自定义短链表

      不建议在原有的表中添加一列表示自定义短链,因为自定义短链的使用相对较少,否则会导致表中大量空缺。所以直接新建一个表吧~

DROP TABLE IF EXISTS `test_custom`; CREATE TABLE `test_custom` ( `id` int(11) NOT NULL AUTO_INCREMENT, `custom_url` varchar(6) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '自定义短链', `long_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '长链', PRIMARY KEY (`id`) USING BTREE, UNIQUE INDEX `custom_long_unq`(`custom_url`, `long_url`) USING BTREE COMMENT '建立自定义url和长链的唯一索引,防止重复' ) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic; 

交互图

      在短链的跳转部分与之前发生了一些改变,需要先查询custom表,判断是否是自定义短链。
请输入图片描述

301 or 302?

      从计算机网络了解到重定向有301重定向和302重定向,并且短网址系统中也有使用这两种重定向方式的,到底应该选择哪种重定向方式呢?

  • 301,代表 永久重定向,也就是说第一次请求拿到长链接后,下次浏览器再去请求短链的话,不会向短网址服务器请求了,而是直接从浏览器的缓存里拿,这样在 server 层面就无法获取到短网址的点击数了,如果这个链接刚好是某个活动的链接,也就无法分析此活动的效果。所以我们一般不采用 301。
  • 302,代表 临时重定向,也就是说每次去请求短链都会去请求短网址服务器(除非响应中用 Cache-Control 或 Expired 暗示浏览器缓存),这样就便于 server 统计点击数,所以虽然用 302 会给 server 增加一点压力,但在数据异常重要的今天,这点代码是值得的,所以推荐使用 302!
小讯
上一篇 2025-04-07 17:55
下一篇 2025-01-26 13:27

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/15548.html