" />
文章

一篇文章说清楚,短链服务实现思路与简单示例

mindmap root((短链服务)) 生成短链 校验长链合法性 计算哈希(MurmurHash) 62进制转换 处理哈希冲突 重定向访问 查找映射关系 302跳转 数据采集 监控统计 记录访问信息(IP/User-Agent等) PV/UV/来源统计 数据可视化

一、整体思路概述

  • 生成短链

    • 对输入的长链进行校验,避免恶意链接或无效链接。

    • 使用非加密型哈希算法(如 MurmurHash3)对长链进行哈希计算,得到 32 位哈希值。

    • 将哈希值转换成 62 进制字符串(字符集通常是 [0-9][A-Z][a-z]),以此作为短链标识。

    • 可能存在哈希冲突的情况:可拼接随机字符串或分布式 ID 重新生成。

    • 将短链与长链的映射关系存储在数据库及缓存(可选)中。

  • 重定向访问

    • 用户访问类似 https://yourdomain.com/s/xxxx 的短链。

    • 服务端根据短链标识去数据库或缓存查询对应长链。

    • 若存在对应的长链,就使用 HTTP 302 做临时重定向,并统计访问信息(IP、时间、来源等)。

  • 监控与统计

    • 在重定向逻辑中,可以调用监控服务收集短链访问信息。

    • 可以通过直接写数据库或异步化的方式(消息队列/日志)积累访问日志。

    • 后台可基于此数据进行 PV/UV、来源、浏览器类型等多维度统计分析,做成可视化报表。

二、示例代码

下面以 Spring Boot 为例,演示一个最简化的短链重定向控制器和哈希生成工具类。

1. 工具类:MurmurHashUtil

public class MurmurHashUtil {

    // 这里以 MurmurHash3 32-bit 版本做演示,使用 Google Guava 或相似库
    public static long hash32(String data) {
        int seed = 0x1234ABCD;
        return Hashing.murmur3_32_fixed(seed)
                      .hashUnencodedChars(data)
                      .padToLong();
    }

    // 将 32 位整型转换为 62 进制字符串
    public static String toBase62String(long hashValue) {
        // 考虑到 hashValue 可能为负数,可以做一下取绝对值处理
        long num = hashValue & 0x00000000ffffffffL;
        String chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
        StringBuilder sb = new StringBuilder();
        while (num > 0) {
            int remainder = (int) (num % 62);
            sb.append(chars.charAt(remainder));
            num = num / 62;
        }
        return sb.reverse().toString();
    }
}
  • hash32(String data) 使用 MurmurHash3 算法生成 32 位哈希值。

  • toBase62String(long hashValue) 将哈希值转为 62 进制字符串,以减少长度并支持大小写数字组合。

2. Controller:ShortController

/**
 * @author zhiweicoding.xyz
 * @date 28/12/2024
 * @email diaozhiwei2k@gmail.com
 */
@Slf4j
@RestController
@RequestMapping("/s")
public class ShortController {

    @GetMapping("/{shortKey}")
    public void redirectUrl(@PathVariable("shortKey") String shortKey,
                            HttpServletRequest request,
                            HttpServletResponse response) throws IOException {

        log.info("shortKey: {}", shortKey);
        // 1. 根据短链 key 查询长链

        //假设去获取来的
        String longUrl = "https://zhiwei.plus/archives/1733061010367";
        if (longUrl == null) {
            // 可返回一个 404 页面
            response.sendError(HttpServletResponse.SC_NOT_FOUND, "短链不存在");
            return;
        }

        // 2. 统计监控数据 (访问者ip, 浏览器信息, referrer 等)
//        urlMonitorService.collect(shortKey, request);

        // 3. 做 302 临时重定向
        response.setStatus(HttpServletResponse.SC_FOUND); // 302
        response.setHeader("Location", longUrl);
    }
}
  • 通过 @GetMapping("/{shortKey}") 捕获短链访问请求。

  • 从数据库/缓存获取真实长链地址,若不存在则返回 404。

  • 若存在则执行 302 重定向,并在此处可调用监控服务收集访问数据。

3. 生成短链逻辑示例

在实际生产环境中,生成短链流程通常类似下面伪代码:

public String generateShortKey(String longUrl) {
    // 1. 合法性校验,排除黑名单域名/过期链接等
    // ...

    // 2. 计算哈希
    long hashVal = MurmurHashUtil.hash32(longUrl);
    String base62 = MurmurHashUtil.toBase62String(hashVal);

    // 3. 检查是否冲突(根据base62查询数据库,若已存在且长链不同,冲突)
    // 若冲突,则拼接随机字符串或分布式ID重新计算
    // ...

    // 4. 保存数据库 & 缓存
    // ...
    return base62;
}

三、监控与统计思路

  • 最简单:直接在 ShortController 里统计点击量,或者更新数据库字段 visit_count

  • 进阶:将访问日志(ip、referer、ua 等)插入数据库或写入消息队列异步处理,避免高并发下的数据库压力。

  • 高级:配合大数据平台进行流式或离线统计,做成可视化报表。

四、总结

  1. 核心要点

    • 哈希生成:MurmurHash + 62 进制转换,生成较短的标识字符串。

    • 短链->长链映射:使用关系型数据库(MySQL/PostgreSQL)或者 NoSQL(Redis)进行存储。

    • 重定向:使用 302 临时重定向,让浏览器下次依旧先访问短链,从而方便后续统计分析。

    • 监控统计:收集访问信息,用于广告效果追踪、业务数据分析。

  2. 可扩展方向

    • 自定义短链、多域名映射、防止恶意爬虫、访问权限控制、接口限流等。

    • 结合缓存、分布式部署提升吞吐量和可用性。

License:  CC BY 4.0