网站首页 > 教程文章 正文
前言
短链接(Short URL)是一种通过缩短网页链接长度来方便分享的技术。相比于传统的长链接,短链接更简洁明了,更易于在社交媒体等平台上分享和传播。在本文中,我们将会详细解释短链接的定义、作用及其构成原理。
短链接的定义
短链接是指将原本的长网页链接通过转化处理成一段更短的字符编码,简化原链接的访问路径,例如将
https://mp.weixin.qq.com/s/PgJyQO8LEhx47IJqFjaV1w 转化为短链接:https://9e6.cn/1。这个短链接通常由几个字符组成,以便在分享时节省字符数和提高可读性。虽然短链接已经存在了一段时间,但它在社交媒体中的广泛使用已经使它成为许多人的熟悉工具。
短链接的作用
1、短链接不仅易于分享,还可以提高可读性。在社交媒体和其他共享平台上,链接通常限制字符数量,短链接能够在丰富文本的同时保持链接的可用性。例如,通过短链接更容易在 Twitter、微博、Instagram 等应用程序中分享链接。
2、通过使用短链接,可以掩盖长URL。它可以帮助防止诈骗攻击等恶意行为。因为这一点,短链接的使用得到了很多的认可。
短链接的构成原理
我们使用百度搜索"hello world",链接为 https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=0&rsv_idx=1&tn=baidu&wd=hello%20world&rsv_pq=8487bffe00068c60&rsv_t=
a9e0f5b6haiMQwAi4N2y8PHDv37rM6sjjKrHJb6KdMGg2dQuUjAnmSEnXtE&rqlang=cn&rsv_enter=1&rsv_sug3=10&rsv_sug1=9&rsv_sug7=100。然后用百度短链接服务压缩一下上面的长链接,压缩后的链接为:http://dwz.cn/5DDXhH。可以看到,压缩后的链接长度比原链接明显变短了。
操作流程就是对 原URL 进行运算,得到一个较短的唯一字符编码,并将其附加到短链接的域名之后,形成一个短链接。
常见的短链接压缩算法
常见的短链接压缩算法有两种,第一种是对 URL 进行hash运算,在得到的hash值上做进一步运算,得到一个较短的hash值。hash运算简单易实现,但是有一定的冲突率。随着 URL 压缩数量的增加,冲突数也会增加,最终导致一部分用户跳转到错误的地址上,影响用户体验。这里的 hash 算法我们选择比较有代表性的 MurMurHash,是一种简单、高效、散列均匀的算法,众多开源框架中都采用了这种算法,比如 Redis。
package org.example.controller;
import cn.hutool.core.util.HashUtil;
public class ShortLink {
public static void main(String[] args) {
String url = "https://www.toutiao.com/c/user/token/MS4wLjABAAAAemUlIefV8HQP3wf9cclqau8z9BkHS72bBLC1bYW3cCY/?source=list&log_from=887a4ccca794f_1719837932675";
// MurmurHash算法32-bit实现
int num = HashUtil.murmur32(url.getBytes());
System.out.println(num);
System.out.println(to62HEX(num));
}
private static String to62HEX(int num) {
num = Math.abs(num);
String chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
StringBuilder sb = new StringBuilder();
int remainder;
while (num > 62 - 1) {
remainder = num % 62;
sb.append(chars.charAt(remainder));
num = num / 62;
}
sb.append(chars.charAt(num));
return sb.reverse().toString();
}
}
第二种是通过数据库自增ID或分布式key-value系统模拟发号器进行发号压缩URL。两种方式各有优劣。发号器发号压缩 URL 优缺点恰好和hash压缩算法相反,优点是不存在冲突问题。缺点是,实现上稍复杂,要协调发号器取初始号。
使用发号策略压缩URL
发号策略是这样的,当一个新的链接过来时,发号器发一个号与之对应。往后只要有新链接过来,发号器不停发号就好。举个例子,第一个进来的链接发号器发0号,对应的短链接为 xx.xxx/0,第二个进来的链接发号器发1号,对应的短链接为 xx.xxx/1,以此类推。发号器发出的10进制号需要转换成62进制,这样可以大大缩短号码转换成字符串后的长度。比如发号器发出 10,000,000,000 这个号码,如果不转换成62进制,直接拼接在域名后面,得到这样一个链接 xx.xxx/10000000000。将上面的号码转换成62进制,结果为AOYKUa,长度只有6位,拼接得到的链接为 xx.xxx/AOYKUa。可以看得出,进制转换后得到的短链接长度变短了一些。6位62进制数,对应的号码空间为626,约等于568亿。也就是说发号器可以发568亿个号,这个号码空间应该能够满足多数项目的需求了,所以基本上不用担心发号器无号可发的情况。上述是发号策略压缩URL的原理,实际在写代码的过程中还需要考虑很多细节,比如缓存,存储等。
需求设计
上面我们讲到了短链的基本原理,实际场景变化万千,我们来看看通常情况下,你在设计短链的时候需要考虑到哪些问题。
1、唯一:给定原始的长 URL ,短链服务能生成比它短且唯一的 URL,即 短链
2、映射:用户点击短链 , 能跳转到原始的长 URL
3、过期:短链经过一定时间后,会过期
4、REST API:接口需要设计成 REST API
考虑的问题?
1、过期:短链一般都不是长期有效的,3个月、6个月、一年 … 处理方式很多,你可以定期手动删除、任务定时检查删除 …
2、安全:短链不可被预测,否则简单的遍历就能把所有短链都遍历完,空耗系统资源。因此,常见的递增主键的方式一般不能采用。
3、高性能:生成短链的过程,以及从短链跳转到原始 URL 要近实时,你可以考虑预先生成足够多的短链、映射关系缓存等等 …
4、高可用:服务不能存在单点故障,如果你的请求量比较大或者要求低容错率,一般你需要考虑集群部署,分散单节点的压力。
5、系统容量预估:需要提前预估你的需求场景,尤其是量大的时候,如何快速存、快速取是一个设计要点。
短链接实现
数据表定义
# 短链表
create table `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 '创建时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_short_link` (`short_link`),
UNIQUE KEY `uk_md5` (`long_link_hash`)
) comment '短链表';
其中,short_link 就是我们的短链,通过 short_link 可以找出具体的映射的 long_link(url),然后重定向访问 long_link 即可。
另外,这里我们记录了原始链接的 hash 值,有什么作用?你想,如果你想要判断某个长链接是否已经存在,要去对比原链接吗?太麻烦,直接用 MD5 值来判断,非常方便。
最后,还是建议你从数据库层面确保短链的唯一性,因此,我们这里将 short_link、long_link_hash 字段设置成了唯一键,确保不会出现重复。
生成方法
具体生成短链的方法我们前面已经提过了
public static String genShortLink(String link) {
return to62HEX(HashUtil.murmur32(link.getBytes()));
}
短链跳转原理
首先开发一个简单的 web应用 测试
package org.example.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
@RestController
public class ShortLinkController {
/**
*
* @param shortLink : A6fIF
* @param response
* @throws Exception
*/
@GetMapping("/{shortLink}")
public void link(@PathVariable("shortLink") String shortLink, HttpServletResponse response) throws Exception {
// query redis for shortLink
String longLink = "https://www.toutiao.com/c/user/token/MS4wLjABAAAAemUlIefV8HQP3wf9cclqau8z9BkHS72bBLC1bYW3cCY/?source=list&log_from=887a4ccca794f_1719837932675";
response.sendRedirect(longLink);
}
}
访问地址:http://127.0.0.1/A6fIF,浏览器就会跳转到设定的 longLink 地址。其中A6fIF 是我们生成的短链。
访问流程基本就以下几点:
- 1)客户端通过浏览器访问短链
- 2)服务端返回 301 / 302 重定向码并携带 location= 原链接
- 3)客户端浏览器重新访问原链接
这里啰嗦一下301和302的跳转在短链接服务使用场景下的区别:用户第一次访问某个短链接后,如果服务器返回301状态码,则这个用户在后续多次访问同一短链接时,浏览器会直接请求跳转地址,而不是短链接地址,这样一来服务器端就无法收到用户的请求。如果服务器返回302状态码,且告知浏览器不缓存短链接请求,那么用户每次访问短链接,都会先去短链接服务端取回长链接地址,然后在跳转。从语义上来说,301跳转更为合适,因为是永久跳转,不会每次都访问服务端,还可以减小服务端压力。但如果使用301跳转,服务端就无法精确搜集用户的访问行为了。相反302跳转会导致服务端压力增大,但服务端此时就可精确搜集用户的访问行为。基于用户的访问行为,可以做一些分析,得出一些有意思的结论。比如可以根据用户IP地址得出用户区域分布情况,根据User-Agent消息头分析出用户使用不同的操作系统以及浏览器比例等等。
猜你喜欢
- 2025-05-16 2021年末,写给计算机系大四学弟学妹!超级干货(建议收藏)
- 2025-05-16 破解HLS低延时的密匙: HLS+技术解密(一)
- 2025-05-16 Spring Security 简单教程以及实现完全前后端分离
- 2025-05-16 揭秘黑产“箱子后门”背后的产业链
- 2025-05-16 seo经验:交换友情链接终极技巧大全
- 2025-05-16 HTTP与HTTPS的区别,详细介绍
- 2025-05-16 「黑客编程」手把手教你编写POC
- 2025-05-16 Moz专家:如何将五个网站迁移至一个新域名
- 2025-05-16 想做好SEO?你必须掌握的10个基础知识上集
- 2025-05-16 想学渗透学不会?手把手教你渗透实战流程
- 05-162021年末,写给计算机系大四学弟学妹!超级干货(建议收藏)
- 05-16破解HLS低延时的密匙: HLS+技术解密(一)
- 05-16Spring Security 简单教程以及实现完全前后端分离
- 05-16揭秘黑产“箱子后门”背后的产业链
- 05-16seo经验:交换友情链接终极技巧大全
- 05-16HTTP与HTTPS的区别,详细介绍
- 05-16「黑客编程」手把手教你编写POC
- 05-16Moz专家:如何将五个网站迁移至一个新域名
- 最近发表
- 标签列表
-
- location.href (44)
- document.ready (36)
- git checkout -b (34)
- 跃点数 (35)
- 阿里云镜像地址 (33)
- qt qmessagebox (36)
- md5 sha1 (32)
- mybatis plus page (35)
- semaphore 使用详解 (32)
- vue @scroll (38)
- 堆栈区别 (33)
- 什么是容器 (33)
- sha1 md5 (33)
- navicat导出数据 (34)
- 阿里云acp考试 (33)
- 阿里云 nacos (34)
- redhat官网下载镜像 (36)
- srs服务器 (33)
- pico开发者 (33)
- https的端口号 (34)
- vscode更改主题 (35)
- 阿里云资源池 (34)
- os.path.join (33)
- redis aof rdb 区别 (33)
- 302跳转 (33)