1.前言
长地址:
就是页面请求实际的地址。如知乎某文章https://www.zhihu.com/question/20103344
短地址:
特定长地址缩短后对应的长度很短的地址,基本上可以理解为一一对应关系
如https://www.zhihu.com/question/20103344的短地址为 http://dwz.date/am7a
备注:
上述地址是由新浪地址转换平台提供的,对于同一个长地址,不同的转换平台生成的短地址不一样,
同一个平台不同时间长成的短地址也可能不一样
2.使用场景
微博上发送新微博内容时,限制字数为140字,如果需要分享链接,那么很长的链接会导致内容篇幅缩小,而且url本身也可能超过140个字,所以如果把地址转换为短地址,那么用户输入短地址,看到的是和输入长地址一样的页面信息,那么用户体验会变好。
发送推广短信时超出70字算两条短信,费用增加,长链接也影响用户体验
综上
在特定场景下,需要能够把长连接转换为短链接
用户输入短链接的效果和长连接一样(浏览器后台重定向)
短链接需要长期有效(或者一定时间内,如1天内有效)
对于同样的长链接,生成的短链接需要一样(或者在一定时间内一样)
3.实现必要条件(基于本博客所用方案而言的必要条件)
1.有一个独立的域名系统,用于拼接完整的短链接,以后后续反查长链接地址
2.一个id发号器(生成树数字保持唯一),如数据库的自增序列
4.实现方案
a.将长链接字符串插入数据库,使用sequence递增序列作为主键,然后返回主键id
或者是先从发号器取出一个新的id,插入id和长链接字符串(两个字段,且id为主键)
b.将主键id进行62进制编码(10数字+26大写字母+26小写字母,一般url用这些表示)
c.使用自身域名信息+62进制字符串拼接为完整的url,然后返回
解析:
客户请求短链接时,时间是寻址短链接域名发送到我们的系统上,
然后根据链接后面的url后缀,转换为10进制,去数据库查询这个主键,找出长链接,
然后返回给客户端,且返回码为301/302(浏览器会自动重定向到长链接地址,用户无感知).
5.优化方案
上面有两个问题未解决:
a.发号器可能会成为瓶颈
b.对于同样的长链接,生成的短链接不一样
解决办法:
a.发号器问题
可以多用几个发号器,各自发号不重复即可。
如10个发号器,则发号尾号是1,2,3,4,5,6,7,8,9,0
即发号进制等于发号器的数量,如果发号器只有一个,那么每次发号数增加1.
b. 短链接不一样的问题
方案一:内存存放LinkedHashMap,key为长链接,value为短链接,
考虑到内存问题,那么只能存放一定数量的键值对,使用LRU进行驱逐。
这样,在一定时间内,某个长链接生成的短链接一直不变。
方案二:(考虑到要求长链接对应的短链接要永久一样)
存入数据库时,除了唯一id和长链接地址外,使用长链接生成64位hashcode,然后一并存入数据库,并且添加索引
下次插入数据库之前,先查询hashcode列是否有这个值,有的话则取出比较value是否相等,
这里可能是hash冲突,实际上不是同一个长链接,但是使用64位hashcode的话,冲突概率会小很多,
这里使用hashcode做索引,而不是直接使用长链接本身,是考虑到长链接比较长,作为索引的话,会导致索引层级加深,需要增加额外的磁盘寻址
6.产品举例
- 新浪:http://sina.lt/
- 百度:http://dwz.cn/
- 0x3:http://0x3.me/
- MRW:http://mrw.so/
新浪长地址转短地址,使用结果如下:
https://www.zhihu.com/question/20103344 生成的短地址为: am7a
https://www.kanzhun.com/employee/gsl1194828/1587907702/ 生成的短地址为:am7c
使用短链接去请求页面: