浅谈短链接设计

随着互联网的普及,尤其是移动互联网的发展,如今我们每个人都要和各种各样的网站、APP打交道,每天都会收到很多服务、营销等信息,有邮件、短信、微信推送等,其中短信应该是接触最频繁的,毕竟除了正经的短信外,还有很多不良信息甚至有害信息源源不断地发送到我们的手机上。

不知道大家有没有注意,我们经常可以在服务类短信的最后可以看到一个链接,通常是xx活动链接或xx账单链接,而且基本上都很简短,有些甚至只有几个字母,如下图中的中国电信链接,当我们点击链接时,往往会跳转到另一个网址,并且网址链接会比短信中的要长很多,这里其实就是使用的短链接。

  • 短信中的短链接

  • 实际跳转网址


为什么要使用短链接

  1. 短信文本过长会拆分成多条计费,而网址链接一般都比较长,使用短链接能有效降低企业成本

  2. 某些内容平台限制文本长度

  3. 降低网络传输成本,文本越长,消耗的网络资源也越多

  4. 将链接转为二维码,如果链接过长,生成的二维码会难以识别

  5. 某些平台对长链接识别不友好


短链接原理

  1. 根据上面图片可以看到,点击短链接后,会向服务器发起一个请求,服务器返回的状态码为302,并且在responseLocation属性返回了实际网址,这里用到的就是302重定向
  2. 重定向分为301重定向和302重定向,301是永久重定向,即首次访问后,每次访问不再请求服务器,而是直接根据浏览器缓存跳转到对应的页面;302是临时重定向,即每次访问都会重新请求服务器
  3. 对长链接进行压缩,最常见的就是使用哈希,当然使用其他的算法也可以,比如MD5、SHA等,对于短链接我们关心的是效率,所以使用一般的哈希函数就可以了
  4. 生成短链接后,我们需要在数据库保存短链接和长链接的映射关系,这样在重定向时才知道应该向浏览器返回哪个长链接

知道了原理后,我们可以自己模仿实现上面的效果


开始动手

  1. 创建一个web工程,这里为了方便,直接创建一个SpringBoot项目,引入guava和redis依赖,我们使用guava的哈希算法生成哈希值,使用redis来保存链接数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.0.1-jre</version>
    </dependency>

    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
  2. 编写BizController负责生成短链接

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    @RestController
    @RequestMapping(value = "/biz")
    public class BizController {

    @Resource
    StringRedisTemplate stringRedisTemplate;

    @GetMapping(value = "/generateShortUrl")
    public String generateShorUrl() {
    // 这里使用SpringBoot的官方文档页面作为要重定向的长链接网址
    String longUrl = "https://docs.spring.io/spring-boot/docs/2.7.11/reference/html/getting-started.html#getting-started";

    // 使用guava提供的哈希工具类对长链接进行压缩,这里使用的是murmur3_32_fixed算法,它会生成32位的哈希值,当然也可以使用其他哈希算法,
    String shortUrl = Hashing.murmur3_32_fixed().hashBytes(longUrl.getBytes()).toString();

    // 将短链接和长链接的映射关系保存到redis中,实际开发中可以保存到MySQL数据库,这里为了演示方便直接使用redis
    stringRedisTemplate.opsForValue().set(shortUrl, longUrl);

    return "shorUrl: http://127.0.0.1:8080/short/" + shortUrl;
    }

    }
  3. 编写ShortUrlController负责重定向

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    @RestController
    @RequestMapping(value = "/short")
    public class ShortUrlController {

    @Resource
    StringRedisTemplate stringRedisTemplate;

    @GetMapping(value = "/{url}")
    public void redirect(@PathVariable("url") String url, HttpServletResponse response) {
    // 从数据库获取短链接对应的长链接,这里用redis演示
    String longUrl = stringRedisTemplate.opsForValue().get(url);
    if (Strings.isEmpty(longUrl)) {
    response.setStatus(HttpStatus.NOT_FOUND.value());
    }

    // 设置状态码为302
    response.setStatus(HttpStatus.FOUND.value());
    // 设置Location为长链接
    response.setHeader(HttpHeaders.LOCATION, longUrl);
    }

    }
  4. 测试


总结

  1. 使用短链接可以为我们带来很多好处
  2. 生成短链接的方式有很多,除了哈希算法外,还可以使用数据库自增id、redis自增、UUID、雪花算法等,每种方法各有有点,根据自身需求合理选择
  3. 生成的短链接需要保证其唯一性,使用MySQL数据库,可以为短链接字段设置唯一索引,使用其他方式需要自己实现方法保证短链接唯一