短链是什么原理?怎么实现呢?
目录
- 一、为什么需要短链
- 二、短链跳转访问原理
- 三、短链生成实现方案
- 1、自增序列算法
- 2、Hash算法
- 四、代码示例
- 1、表结构及索引
- 2、外部依赖
- 3、Base62Utils
- 4、DAO层
- 5、业务层
- 五、测试用例
一、为什么需要短链
内容营销中给用户推送营销消息最常见的方式就是发短信,比如三大运营商移动、联通、电信平时会发送一些诸如套餐办理、消费查询、话费充值这些短信,还有像银行、云服务厂商等等推送的各种包含查询服务的短信等等。
我们都知道单条短信发送的内容长度是有限制的,而如果要推送包含URL的消息,如果URL太长,不仅影响用户观感,而且会占用太多无用字数。
这时,我们需要将长的URL转换为短URL,也就是接下来我们要说的短链(短域名
+ 短请求路径
)。
二、短链跳转访问原理
原理还是很简单的,其实就是在后台保存有短链和长链的映射关系,然后进行重定向,让浏览器跳转到对应的长链接。
举个栗子,原始长链接为:https://www.baidu.com,通过某平台我生成了一个短链接:https://suo.nz/378IQe。
我们可以看到当访问https://suo.nz/378IQe时,后端返回了302
,同时多了一个Location
响应头,值就是原始链接https://www.baidu.com.
这里有个小问题,关于重定向使用301还是302?
编码 | 含义 | 备注 |
---|---|---|
301 | Moved Permanently | 永久重定向,表示原 URL 不再被使用,而应该优先选用新的 URL,搜索引擎会直接更新与该资源相关的URL,一般用于网站重构。 |
302 | Found | 临时重定向,搜索引擎不会记录该资源对应的临时链接,一般用于由于不可预见的原因导致该页面暂不可用。 |
301其实是比较符合HTTP协议语义的,但浏览器会缓存目标网址,下次访问时会直接跳过短链,跳转到目标网址,无法做一些统计,比如短链访问次数等。
302:浏览器访问时,会先后访问短链代理服务和目标服务,对服务器的压力也就相应大些,但可以做一些统计。
备注:很多短链生成平台其实都是走的
302
重定向。
三、短链生成实现方案
1、自增序列算法
常用的自增序列算法有雪花算法、Redis自增、MySQL主键自增等,生成唯一ID后,再转换为62进制字符串,转换后的62进制字符串可用作短链。
问题:为什么需要转换为62进制字符串呢?
因为自增ID会越来越长,经过62进制转换后可以变得更短。
现在说下关于自增序列生成短链的优缺点:
- 优点:ID唯一,生成的短链不会重复和冲突。
- 缺点:随着ID越来越大,短链长度也会随之变化,长度不固定。
再说下各种自增序列算法的优缺点:
算法 | 优点 | 缺点 |
---|---|---|
雪花算法 | 高性能,不依赖任何中间件 | 存在系统时钟回拨问题,原始雪花算法长度为64位,生成的ID比较长。 |
Redis自增 | 高性能,高并发 | 既然是中间件,有维护成本,同时要考虑持久化、灾难恢复等。 |
MySQL主键自增 | 使用简单,易于扩展 | 高并发下有性能瓶颈 。 |
- 301其实是比较符合HTTP协议语义的,但浏览器会缓存目标网址,下次访问时会直接跳过短链,跳转到目标网址,无法做一些统计,比如短链访问次数等。
- 302:浏览器访问时,会先后访问短链代理服务和目标服务,对服务器的压力也就相应大些,但可以做一些统计。
2、Hash算法
简单来说就是对目标长链接进行hash,然后再对hash值进行62进制编码转换为短链接。Hash算法我们熟知的有MD5
、SHA
等算法。
这两种算法为加密型hash算法,性能相对比较低,这里我们一般采用Google Guava
中实现的Murmurhash
算法,该算法为非加密型hash算法,相比MD5
优点如下:
- 速度比MD5快。
- 哈希冲突的概率低,该算法支持32位和128位哈希值,MD5也是128位哈希值,基本不用担心哈希冲突。
- 离散度高,散列值比较均匀。
关于Murmurhash
示例如下:
String url = "https://www.baidu.com/";// 输出:e9ac4fbdc398e8c104d1b8415f42cbf8
System.out.println(Hashing.murmur3_128().hashString(url, StandardCharsets.UTF_8));
// 输出:06105412
System.out.println(Hashing.murmur3_32_fixed().hashString(url, StandardCharsets.UTF_8));
// 输出:bf447182
System.out.println(Hashing.murmur3_32_fixed().hashLong(Long.MAX_VALUE));// 转成Long型// 输出:307499014
System.out.println(Hashing.murmur3_32_fixed().hashString(url, StandardCharsets.UTF_8).padToLong());
// 输出:2188461247
System.out.println(Hashing.murmur3_32_fixed().hashLong(Long.MAX_VALUE).padToLong());
这里说下通过Hash算法生成短链的优缺点:
- 优点:去中心化,哈希后生成的短链长度基本固定。
- 缺点:有概率会发生哈希冲突,解决哈希冲突的方法主要有
拉链法
和重新哈希
。由于短链是通过哈希值转62进制字符串生成,如果发生哈希冲突,得重新哈希生成。如果存库的话,每次生成短链至少会有一次查询和一次保存操作,有性能损耗。
四、代码示例
接下来的示例我们主要用Hash
算法 + Base62
编码生成短链,流程图如下:
1、表结构及索引
# 短链信息表
create table `t_short_link`
(`id` bigint primary key auto_increment comment '主键ID',`short_link` varchar(32) not null default '' comment '短链接',`long_link_hash` bigint not null default 0 comment 'hash值',`long_link` varchar(128) not null default '' comment '长链接',`status` tinyint not null default 1 comment '状态:1-可用,0-不可用',`expiry_time` datetime null comment '过期时间',`create_time` datetime not null default current_timestamp comment '创建时间'
) comment '短链信息表';
create index idx_sl_hash_long_link on t_short_link (long_link_hash, long_link);
create index idx_sl_short_link on t_short_link (short_link);
2、外部依赖
<!--Google Guava-->
<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>31.1-jre</version>
</dependency>
3、Base62Utils
public abstract class Base62Utils {private static final int SCALE = 62;private static final char[] BASE_62_ARRAY = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M','N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z','a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm','n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z','0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};private static final String BASE_62_CHARACTERS = String.valueOf(BASE_62_ARRAY);/*** 将long类型编码成Base62字符串* @param num* @return*/public static String encodeToBase62String(long num) {StringBuilder sb = new StringBuilder();while (num > 0) {sb.insert(0, BASE_62_ARRAY[(int) (num % SCALE)]);num /= SCALE;}return sb.toString();}/*** 将Base62字符串解码成long类型* @param base62Str* @return*/public static long decodeToLong(String base62Str) {long num = 0, coefficient = 1;String reversedBase62Str = new StringBuilder(base62Str).reverse().toString();for (char base62Character : reversedBase62Str.toCharArray()) {num += BASE_62_CHARACTERS.indexOf(base62Character) * coefficient;coefficient *= SCALE;}return num;}
}
备注:
BASE_62_ARRAY
中的字符顺序可以随便打乱,不一定要按顺序排列,打乱安全性更高。
问题:能不能用Base64
编码生成短链呢?
JDK8中Base64.getEncoder()
获取到的编码器对应的编码字符会包含'+'
、'/'
等URL不允许包含的特殊字符,但Base64.getUrlEncoder()
获取到的编码器对应的编码字符会把'+'
、'/'
分别替换成'-'
、'_'
,所以其实也是可以的。如下:
4、DAO层
@Repository
public class ShortLinkManagerImpl implements ShortLinkManager {@Autowiredprivate ShortLinkMapper shortLinkMapper;@Overridepublic void saveShortLink(String shortLink, long longLinkHash, String longLink) {ShortLinkDO shortLinkDO = ShortLinkDO.builder().shortLink(shortLink).longLinkHash(longLinkHash).longLink(longLink).status(true).build();shortLinkMapper.insert(shortLinkDO);}@Overridepublic String getShortLink(long longLinkHash, String longLink) {Wrapper<ShortLinkDO> wrapper = Wrappers.lambdaQuery(ShortLinkDO.class).select(ShortLinkDO::getShortLink).eq(ShortLinkDO::getLongLinkHash, longLinkHash).eq(ShortLinkDO::getLongLink, longLink).last(CommonConst.LIMIT_SQL);ShortLinkDO shortLinkDO = shortLinkMapper.selectOne(wrapper);return Optional.ofNullable(shortLinkDO).map(ShortLinkDO::getShortLink).orElse(null);}@Overridepublic boolean isShortLinkRepeated(String shortLink) {Wrapper<ShortLinkDO> wrapper = Wrappers.lambdaQuery(ShortLinkDO.class).eq(ShortLinkDO::getShortLink, shortLink);return shortLinkMapper.selectCount(wrapper) > 0;}
}
5、业务层
@Service
public class ShortLinkServiceImpl implements ShortLinkService {@Autowiredprivate ShortLinkManager shortLinkManager;@Overridepublic String generateShortLink(String longLink) {long longLinkHash = Hashing.murmur3_32_fixed().hashString(longLink, StandardCharsets.UTF_8).padToLong();// 通过长链接Hash值和长链接检索String shortLink = shortLinkManager.getShortLink(longLinkHash, longLink);if (StringUtils.isNotBlank(shortLink)) {return shortLink;}// 如果Hash冲突则加随机盐重新Hashreturn regenerateOnHashConflict(longLink, longLinkHash);}private String regenerateOnHashConflict(String longLink, long longLinkHash) {// 自增序列作随机盐long uniqueIdHash = Hashing.murmur3_32_fixed().hashLong(SnowFlakeUtils.nextId()).padToLong();// 相减主要是为了让哈希值更小String shortLink = Base62Utils.encodeToBase62String(Math.abs(longLinkHash - uniqueIdHash));if (!shortLinkManager.isShortLinkRepeated(shortLink)) {shortLinkManager.saveShortLink(shortLink, longLinkHash, longLink);return shortLink;}return regenerateOnHashConflict(longLink, longLinkHash);}}
五、测试用例
@SpringBootTest(classes = Application.class)
public class ApplicationTest {@Autowiredprivate ShortLinkService shortLinkService;@Testpublic void generateShortLinkTest() {String shortLink = shortLinkService.generateShortLink("https://www.baidu.com/");System.err.println("生成的短链为:" + shortLink);}
}
控制台输出:
生成的短链为:D4PTSU
备注:生成的短链长度基本为6位字符串,还有记得短链代理服务选一个
短域名
。
短链是什么原理?怎么实现呢?相关推荐
- 快速理解简单的短链接生成原理
快速理解简单的短链接生成原理 原理 计算长链接整体为一个十进制数,将其映射成一个62进制数.这个62进制由26个小写字母,26个大写字母和10个数字表示. 假设有long-url这么一个长网址,其10 ...
- java 短链跳转原理_给你代码:短链接生成原理
短链接,顾名思义就是在形式上比较短的链接.最早存在于微博(如新浪微博,t.cn,url.cn)分享网址中.比如这样的:t.cn/Aidjddvo 短链接的好处 内容需要(比如短信,微博中链接字数的限制 ...
- 跨平台应用开发进阶(五十八):短链基本工作原理与实现方案
文章目录 一.短链是什么 二.为什么要使用短链 三.短链跳转基本原理 四.短链实现步骤 五.使用哈希算法生成短链 5.1 其他方法生成短链 5.2 实现方案 六.短链生成工具 6.1 网站工具:ft1 ...
- 系统设计——如何设计一个高性能的短链接系统?
短链系统设计看起来很简单,但如何设计一个高性能短链系统呢,这也是面试中非常常见的一道设计题. 首先,为什么要用短链? 短链跳转的基本原理是什么? 短链生成的几种方法你知道吗? 高性能短链的架构如何设计 ...
- 短链的基本工作原理描述与实现方案
短链是什么 短链就是普通的长链(普通URL网址)经过一定的处理得到的一个简短且唯一的网址字符串. 短链跳转的基本原理 客户端访问短链网址服务器,短链网址服务器返回对应长链地址和302响应码,客户端收到 ...
- 技术干货 | 高性能短链设计与实现
什么是URL短链 URL 短链,就是把原来较长的网址,转换成比较短的网址.以下面这条短信为例: 上图中,https://dx.10086.cn/looGDg 就是一条短链.用户点击蓝色的链接,就可以在 ...
- 从CSRF原理到CMS漏洞利用
文章目录 0x01 基础知识: 1.CSRF漏洞简介: 2.与XSS的区别: 3.攻击的细节: 4.常见的攻击类型: 4.1.GET类型的CSRF: 4.2.POST类型的CSRF: 0x02 CSR ...
- [html] 你知道短链接的生成原理吗?
[html] 你知道短链接的生成原理吗? 目的将长度较长的链接压缩成较短的链接,并通过跳转的方式,将用户请求由短链接重定向到长链接上去1.二种方式生成短链hash-可能会重复发号器发号压缩 URL2. ...
- [html] 你知道短链接的生成原理吗?
[html] 你知道短链接的生成原理吗? 目的将长度较长的链接压缩成较短的链接,并通过跳转的方式,将用户请求由短链接重定向到长链接上去1.二种方式生成短链hash-可能会重复发号器发号压缩 URL2. ...
最新文章
- 李丽娟c语言第四版教师书_来,把自学C语言经历的那些苦,都踩在脚下
- 用python编写图片生成器_python生成器
- java11模块化开发_【JDK 11】关于 Java 模块系统,看这一篇就够了
- Java多线程(1)--基本概念:程序、进程、线程
- 群论及Polya计数定理题目入门
- javascript -- 判断是否为某个数据类型
- linux下简易搭建svnserver
- MySQL select语句直接导出数据
- 为什么 BetterScroll 初始化不能滚动?
- 20200518 如何快速画出闭环特征方程的根轨迹
- W(hadoop).Permission denied: user=dr.who, access=WRITE, inode=“/output“:root:supergroup:drwxr-xr-x
- 【selenium】126官网邮箱登录
- 文件或目录损坏且无法读取 删除不了 错误0x80070091:目录不是空的 解决方案
- POJ 1062 昂贵的聘礼【经典的最短路问题】
- CTFHUB-WEB-文件上传【06】
- 活动预告丨易盾CTO朱浩齐将出席2018 AIIA大会,分享《人工智能在内容安全的应用实践》
- 数字签名与数字证书技术简介(一)
- win10电脑wifi连不上,一直显示正在检测网络要求
- Vue CLI + VUE +vConsole/eruda 在移动端进行调试
- cmd命令行用copy和xcopy实现文件拷贝/目录复制
热门文章
- FFplay文档解读-5-编解码器选项二
- 来看看中国计算机视觉行业发展有什么动态?
- checkbox选中往后台传1,不选中往后台传0
- [喵咪开源软件推荐(6)]TCP链路加速技术KcpTun
- Linux常用命令速查集锦(菜鸟日常生存自救手册)
- Python渗透测试之ARP毒化和协议应用
- (附源码)Springboot校园二手交易平台 毕业设计191637
- 大数据时代鸿星尔克因系统崩溃恳请顾客退款;微信里可以开借条了;阿里云盘来势汹汹却首战告败?
- 算法报告五--跳马问题
- 计算矩形面积的程序python_python实现用类读取文件数据并计算矩形面积