1:短链接跳转原理
一般以 3xx 开头的代表重定向,表示网页发生了转移,需要重定向到对应的地址中去,两者区别是:
- 301:表示永久性转移(Permanently Moved):第一次访问短链接会调转到短链接服务,然后跳转到目标地址,之后将其放入缓存,之后不在访问短链接服务,直接跳转到目标地址。
- 302:表示临时性转移(Temporarily Moved):每一次访问短链接会调转到短链接服务,方便进行跟踪与数据统计
2:创建短链接表
CREATE TABLE `t_link` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`domain` varchar(128) DEFAULT NULL COMMENT '域名',
`short_uri` varchar(8) DEFAULT NULL COMMENT '短链接',
`full_short_url` varchar(128) DEFAULT NULL COMMENT '完整短链接',
`origin_url` varchar(1024) DEFAULT NULL COMMENT '原始链接',
`click_num` int(11) DEFAULT 0 COMMENT '点击量',
`gid` varchar(32) DEFAULT NULL COMMENT '分组标识',
`enable_status` tinyint(1) DEFAULT NULL COMMENT '启用标识 0:未启用 1:已启用',
`created_type` tinyint(1) DEFAULT NULL COMMENT '创建类型 0:控制台 1:接口',
`valid_date_type` tinyint(1) DEFAULT NULL COMMENT '有效期类型 0:永久有效 1:用户自定义',
`valid_date` datetime DEFAULT NULL COMMENT '有效期',
`describe` varchar(1024) DEFAULT NULL COMMENT '描述',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '修改时间',
`del_flag` tinyint(1) DEFAULT NULL COMMENT '删除标识 0:未删除 1:已删除',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_unique_full_short_url` (`full_short_url`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
//注意short_uri编码字符集类型改为UTF-8这样就区分大小写,UTF-8mb4大小写是一样的。
3:短链接表结构
短链接唯一?
- 全局唯一:单一短链接在所有域名下唯一,全平台唯一。如果有了 a.com/abcdef 就不可以有 b.com/abcdef
- 域名下唯一:单一短链接仅保证域名下唯一。如果有了 a.com/abcdef 也可以有 b.com/abcdef 设置
短链接:/abcdef
保证域名下唯一的原理:
每个短链接的唯一性是基于
full_short_url
列,这列包含完整的短链接(包括域名)。当有多个不同的域名时,即使short_uri
相同,只要domain
不同,组合后的full_short_url
仍然是唯一的。例如,你有两个域名a.com
和b.com
,并且分别生成了短链接abcdef
。两个完整的短链接将是a.com/abcdef
和b.com/abcdef
。由于这两个完整的短链接不同,因此它们不会违反唯一性约束,即在不同域名下,同样的短链接可以重复。保证全局唯一的原理:
不允许任何两个短链接相同,无论是在哪个域名下,需要为短链接本身添加唯一性约束,而不考虑域名。直接在
short_uri
列上添加唯一索引。这意味着无论哪个域名下,都不能重复使用相同的短链接。
4:短链接生成算法
假设我们使用的是 26 个字母的大小写,加上 10 个数字,那么对于短链接可以表示的最大组合数量为:
- N = 4,组合数为 62 ^ 4 = 14_776_336,1477 万左右
- N = 5,组合数为 62 ^ 5 = 916_132_832,9.16 亿左右
- N = 6,组合数为 62 ^ 6 = 56_800_235_584,568 亿左右
生成短链接的时候,只需要生成一个唯一的 10 进制数,然后再基于此 10 进制数转换为 62 进制数即可。
package com.nageoffer.shortlink.project.toolkit;
import cn.hutool.core.lang.hash.MurmurHash;
/**
* HASH 工具类
*/
public class HashUtil {
private static final char[] CHARS = new char[]{
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'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'
};
public static String hashToBase62(String str) {
int i = MurmurHash.hash32(str); //将输入进来的URL转化成一个32位十进制数字 最大32个9 有可能是正数也可能是负数
int num = i < 0 ? Integer.MAX_VALUE - i : i; //int -> 32位
return convertDecToBase62(num); //将32位数字传入后,会返回一个长度为6的短链接
}
private static String convertDecToBase62(int num) {
StringBuilder stringBuilder = new StringBuilder();
int SIZE = CHARS.length;
while(num > 0) {
stringBuilder.append(CHARS[num % SIZE]);
num = num / SIZE;
}
return stringBuilder.reverse().toString();
//进行反转 -> 原:高位在左,低位在右 -> 62位转换后 低位在左,高位在右 -> 进行字符串反转后,可保证高低位顺序一致 , 保证后续反编码的可逆性
}
}
// 32 位整数的最大值是 2的32次方-1 即 2,147,483,647(20亿左右)最小值是负的2的31次方,-2,147,483,648(-20亿多)
// 在这里只有非负数 所以生成的32位数范围是0 - > 20亿多
// 而62的6次方范围是:0 -> 56亿, 所以完全可以放的下32位数的转化 所以最后是6位