专业的短链接生成工具
链接域名
短网址有效期
长链接转换短链接的方式有哪些?
更新时间:2025-5-8 19:10:28 作者:爱短链
短链接,通俗的说,就是通过程序估计等手段,将长 URL 转化为缩写的 URL 字符串。
人们经常会收到一些莫名其妙的营销电子邮件,其中包含一个非常短的链接供您跳转。由于新浪微博上的字符数有限,您经常会看到这些看起来不像网址的网址。短链的盛行应该是微博字数的限制激发了你的创造力。
如果我们需要长链接转换短链接,我们应该怎么做?
第一种方式:直接使用长链接转换短链接在线生成工具生成即可:https://www.aifabu.com (爱短链,安全 稳定 极速访问)
第二种种方式的话,就是自己搭建,这种的话,相对而言是比较复杂的一种
短链接代码通常由 62 个字母或数字组成 [a - z, A - Z, 0 - 9]。短码的宽度也可以定制,但一般不少于8位。最常用的是6位,6位短码已经可以有568亿个组合:(26+26+10)^6 = 56800235584,已经满足了大部分使用场景。
目前比较流行的短码生成方式有:自增id、摘要算法、普通随机数。分布式ID生成器的解决方案总结,这篇文章也可以参考。
自动递增 ID
该方法是一种无碰撞方法。原理是每次添加一个短码,在之前添加的短码id上加1,然后将十进制的id值转换成62位的id值。细绳。
一般是借助数据表中的自增id来完成的:每次先查询数据表中自增id的最大值,对应的长URL的自增id值到被插入的是max+1,将max+1转换成62进制可以得到短码。
但是短码id是从一个bit的宽度递增的,而且短码的宽度不是固定的,但是可以通过从指定数递增id的方法来处理,保证所有的短码都有相同的宽度。同时生成的短码是有序的,可能存在安全问题。生成的短码id可以和长URL等其他关键字进行md5操作,生成最终的短码。
摘要算法
摘要算法,也称为哈希算法,是指输入任意宽度的数据,输出固定宽度的数据。相同的输入数据总是得到相似的输出,不同的输入数据试图得到不同的输出。
算法过程:
从长URL md5生成一个32位的签名串,分为4段,每段8字节;
对于这四个循环,取8个字节,当作16进制字符串和0x3fffffff(30位1)和操作,即忽略小于30位的处理;
30位数字分为6段,每个5位数字作为字母表的索引,得到一个特定的字符,依次得到6位字符串;
总共md5字符串可以得到4个6位字符串;其中任何一个都可以作为这个长url的短url地址;
这个算法,虽然会生成4个,但是还是有重复的机会。
虽然概率很小,但是这种方法还是有冲突的可能,解决冲突会比较麻烦。但是这种方法生成的短码数量是固定的,连续生成的短码没有先后顺序。
普通随机数
方法是从62个字符串中随机选择一个6位短码的组合,然后到数据库中检查该短码是否已经存在。如果已经存在,则继续循环该方法再次获取短码,否则直接返回。
这种方法是最简单的实现,但是因为Math.round()方法生成的随机数是伪随机数,所以碰撞的可能性不小。在数据量很大的情况下,可能会重复多次生成不冲突的短码。
算法分析
我们将一一分析上述算法的优缺点。
如果使用自增 id 算法,就会出现不法分子可以异或你的短链地址的问题。原理是将十进制数转换为62,这样别人可以用类似的方法递归你的短链,得到对应的原链接。
例如:http://tinyurl.com/a3300和http://bit.ly/a3300,这两个短链网站,分别从a3300-a3399,可以多次尝试返回正确的url。因此,这些方法生成的短链对用户来说可能并不安全。
抽象算法实际上是一种哈希算法。说到hash,你可能会觉得很低落,但其实hash可能是最优解。例如:http://www.sina.lt/ 和 http://mrw.so/ 发现连续生成的url不规则,很有可能是用hash算法实现的。
普通随机数算法,这种算法生成的东西和摘要算法一样,但是碰撞的概率会更高。因为digest算法是对url进行hash,而随机数算法就是简单的随机生成,即使数上去了,也肯定会导致重复。
基于以上,我选择了最低的算法:摘要算法(毕竟,长链接转换短链接也是一件麻烦事儿)。
完成
存储解决方案
数据库存储解决方案
短网址的基本数据按域名和后缀分开存储。另外,域名需要区分 HTTP 和 HTTPS,hash 方案对整个链接进行哈希处理,而不是只对域名外的链接进行哈希处理。单独的域名存储可以适用于分析当前域名下的链接使用情况。
增加当前链接有效期。一般来说,短链需求可能是相关的活动或热点。这种短链会在一段时间内非常活跃,一段时间后趋势会继续下降。因此无需永久保留这些链接,以减轻日常查询的负担。
对于过期数据的处理,可以在添加新的短链时确定当前短链的过期日期,在HBase中为每晚到达过期日期的数据创建一张单独的表,当有过期数据时确定过期日期是新的。对应的HBase表就够了,每天只处理当天HBase表中的无效数据。
数据库的基本表如下:
base_urlsuffix_urlshot_codetotal_click_countfull_urlexpiration_date
http://www.aichacha.com
/搜索/12345
edfg3s
http://www.aichacha.com//search/12345
http://www.aichacha.com
/aiCheck/getResult/123
Fe9dq
http://www.aichacha.com//aiCheck/getResult/123
http://www.baidu.com
/文库/12354
lcfr53
http://www.baidu.com/wenku/12354
字段定义:
base_url:域名
suffix_url:链接不只是域名外的后缀
full_url:完整链接
shot_code:当前suffix_url链接的短代码
expiration_date:到期日期
total_click_count:当前链接的总点击次数
expire_date:当前链接过期时间
缓存方案
查询要求
个人觉得缓存上百G的数据是不合适的,所以有一个折中的方案:把最近3个月的查询或者新的URL放到缓存中,使用LRU算法。进行热更新。这样,使用最近使用的概率会命中缓存,所以不需要去图书馆。找不到的时候去图书馆更新缓存。
新需求
对于新的链接,首先检查缓存是否存在,如果缓存不存在,再检查数据库。数据库已经分表了,查询效率不会很低。
缓存设计
查询要求是用户持有短链查询对应的真实地址,那么缓存的key只能是短链,可以用KV方式存储。
(至此,长链接转换短链接已经完成一半了)
杂耍
其实其他存储方案也可以考虑,比如HBase。作为NOSQL数据库,HBase在性能上仅次于redis,但存储成本却比redis低了很多数量级。存储基于 HDFS。写入数据时,会先写入显存,只有显存满时,才会将数据刷新到HFile。
读取数据也更快,因为它使用 LSM 树结构而不是 B 或 B+ 树。HBase 会使用 LRU 算法将最近调用的数据倒入缓存中。如果想提高读取能力,可以增加blockCache。
其次,也可以使用ElasticSearch,适当的索引规则的效果并不逊色于缓存方案。
是否需要分库分表?
单条数据小于10b,1亿条数据总容量约953G。单张表肯定不能稳定这么大的量,所以需要分表。如果你有信心在2年内服务可以达到这个规模,那么你可以从设计之初就考虑表的方案。推荐:对于各大厂商使用的分库分表方案,看这篇文章就够了。
那么如何定义分表的规则呢?
如果按照单表500万条记录计算,一共可以分成20张表,那么单表的容量是47G,还是蛮大的,所以考虑分表的key和单表的容量,如果分成100张这样的单表容量是10G,通过数字后缀路由到表也比较容易。可以对 short_code 进行编码以生成数字类别,然后进行路由。
怎么跳转
当我们在浏览器中输入 bit.ly/a3300
DNS首先解释赢得bit.ly的IP地址
当DNS获取到一个IP地址时(例如:12.34.5.32),会向该地址发送HTTPGET请求,查询短码a3300
【http://bit.ly服务器会通过短码a3300获取对应的长URL
请求通过 HTTP301 转发回对应的长 URL /story/0,25197,26089617-5013871,00.html。
这里有个小知识点,为什么用301跳而不是302跳?
知识点:为什么用302跳而不是301跳?
301是永久重定向,302是临时重定向。短地址一旦生成就不会改变,所以使用 301 符合 http 语义。但是如果使用301、谷歌、百度等搜索引擎,搜索时会直接显示真实地址,那么我们无法统计短地址的点击次数,而且很难收集到用户的Cookie、User Agent和其他信息。这些信息可以用来做有趣的大数据分析,也是短网址服务商的主要利润来源。
附上两个算法:
总结算法:
导入 org.apache.commons.lang3.StringUtils;
导入 javax.xml.bind.DatatypeConverter;
导入 java.security.MessageDigest;
导入 java.security.NoSuchAlgorithmException;
导入 java.util.concurrent.atomic.AtomicLong;
导入静态 com.alibaba.fastjson.util.IOUtils.DIGITS;
公共类 ShortUrlGenerator {
公共静态无效主要(字符串[]参数){
String sLongUrl = "http://www.baidu.com/121244/ddd";
对于(字符串短网址:短网址(sLongUrl)){
System.out.println(shortUrl);
}
}
公共静态字符串 [] shortUrl(字符串 url){
// 可以在生成MD5加密字符前自定义混合KEY
字符串键 = "dwz";
// 用于生成 URL 的字符
字符串[] 字符 = 新字符串[]{“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”、“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”
};
// 传入 URL 的 MD5 加密
字符串 sMD5EncryptResult = "";
尝试 {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update((key + url).getBytes());
字节[] 摘要 = md.digest();
sMD5EncryptResult = DatatypeConverter.printHexBinary(digest).toUpperCase();
} 捕捉(NoSuchAlgorithmException e){
e.printStackTrace();
}
字符串[] resUrl = 新字符串[4];
//获取4组短链接字符串
for (int i = 0; i < 4; i++) {
// 根据一组8个十六进制和0x3FFFFFFF对加密字符进行位与运算
字符串 sTempSubString = sMD5EncryptResult.substring(i * 8, i * 8 + 8);
// 这里需要使用long类型进行转换,因为Inteper.parseInt()只能处理31位,第一位是符号位,不使用long会越界
长 lHexLong = 0x3FFFFFFF & Long.parseLong(sTempSubString, 16);
字符串 outChars = "";
//循环赢得每组6位字符串
for (int j = 0; j < 6; j++) {
// 将得到的值与0x0000003D进行按位与运算,得到字符列表的chars索引(具体取决于chars列表的宽度,防止角标溢出,注意起点为0)
长索引 = 0x0000003D & lHexLong;
// 将得到的字符相乘
outChars += 字符[(int) 索引];
// 每个循环右移 5 位
lHexLong = lHexLong >> 5;
}
// 将字符串存储在对应索引的输出链表中
resUrl[i] = outChars;
}
返回resUrl;
}
}
将数字转换为 base62 算法:
* 十六进制转换工具,最大支持十进制和十六进制转换
* 1、 将十进制数转换为指定的二进制补码字符串;
* 2、 将其他的补数(字符串模式)转换为十进制数
*/
公共类 NumericConvertUtils {
公共静态无效主要(字符串[]参数){
字符串 str = toOtherNumberSystem(22, 62);
System.out.println(str);
}
/**
* 补码表示的字符集,0-Z 适合表示最多十六进制的符号
*/
private static final char[] 数字 = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', '我',
'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 '};
/**
* 将十进制数转换为指定的二进制补码字符串
*
* @param number 十进制数
* @param 种子指定的补码
* @return 指定补码的字符串
*/
public static String toOtherNumberSystem(long number, int seed) {
如果(数字 < 0) {
number = ((long) 2 * 0x7fffffff) + number + 2;
}
字符[] buf = 新字符[32];
int charPos = 32;
而((数字/种子)> 0) {
buf[--charPos] = 数字[(int) (数字 % 种子)];
数字/=种子;
}
buf[--charPos] = 数字[(int) (数字 % 种子)];
return new String(buf, charPos, (32 - charPos));
}
/**
* 将其他的补数(字符串模式)转换为十进制数
*
* @param number 其他的补数(字符串模式)
* @param seed 指定的补码,即参数str的原补码
* @return 十进制数
*/
public static long toDecimalNumber(String number, int seed) {
char[] charBuf = number.toCharArray();
如果(种子 == 10) {
return Long.parseLong(number);
}
长结果 = 0,基数 = 1;
for (int i = charBuf.length - 1; i >= 0; i--) {
整数索引 = 0;
for (int j = 0, 长度 = 数字长度;j < 长度;j++) {
//找到对应字符的角度标签,对应的角度标签就是详细值
如果(数字[j] == charBuf[i]){
指数 = j;
}
}
结果+=索引*基数;
基础 *= 种子;
}
返回结果;
}
}
结束~
以上就是关于《长链接转换短链接的方式有哪些?》的全部内容了,感兴趣的话可以点击右侧直接使用哦!》》在线短链接生成器