短链接生成的核心逻辑是自增ID加Base62编码实现唯一可逆映射,而非哈希;须用数据库主键或Snowflake等稳定ID源,Base62需手写且字符集要避易混淆字符,存储必须加唯一索引防重,跳转优先用302以支持统计与动态修改。

短链接生成的核心逻辑不是加密,而是确定性映射
短链接本质是把长 URL 映射成一个唯一、固定、可逆的短字符串。Java 里最直接的方式不是用 MessageDigest 做哈希再截断(会冲突),而是用自增 ID + Base62 编码——ID 保证唯一和有序,Base62 控制长度且可读性好。
常见错误是直接对原始 URL 调用 hashCode() 或 Objects.hash(),结果不稳定(不同 JVM 实例、不同 Java 版本可能不一致),而且无法反查原链接。
- 必须用数据库主键或分布式 ID 生成器(如
SnowflakeIdGenerator)作为源头 ID - 避免用
String.hashCode():它不满足跨进程/跨版本一致性 - 如果不用数据库,至少用
AtomicLong+ 文件或 Redis 持久化计数器,否则服务重启后 ID 重叠
Base62 编码要手写,别依赖第三方库的“通用进制转换”
Base62 字符集是 0-9a-zA-Z(共 62 个字符),顺序不能错,尤其注意大小写字母区分。很多工具类(比如 Apache Commons Codec 的 BaseNCodec)默认不支持 Base62,强行复用 Base64 逻辑会出错——Base64 有 +、/ 和 =,不适合 URL。
示例关键逻辑:
立即学习“Java免费学习笔记(深入)”;
private static final String BASE62_CHARS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static String encode(long num) {
if (num == 0) return "0";
StringBuilder sb = new StringBuilder();
while (num > 0) {
sb.append(BASE62_CHARS.charAt((int) (num % 62)));
num /= 62;
}
return sb.reverse().toString();
}
- 务必检查
BASE62_CHARS中0O(零和大写 O)和1lI(数字 1、小写 L、大写 i)是否易混淆,生产环境建议去掉0O1lI改用更安全的 56 进制(但长度略增) - 解码时要用
indexOf()查字符位置,别用Character.getNumericValue()——它对字母返回的是 Unicode 数值,不是 Base62 序号 - Base62 结果长度随 ID 增长缓慢:100 万 ID ≈ 5 位,1 亿 ID ≈ 6 位,够用
URL 存储和查询必须加唯一索引,否则短码重复没人兜底
即使 ID 是唯一的,如果编码后没校验存储结果,两个不同 URL 可能偶然生成相同短码(极低概率,但 Base62 编码本身无防重逻辑)。真实场景中更常见的是并发插入导致重复写入——比如两个请求同时拿到 ID=1001,都算出 "aB3x",然后都往 DB 插。
- 数据库表必须给短码字段加
UNIQUE索引,插入失败时捕获SQLIntegrityConstraintViolationException,然后递增 ID 重试 - 不要在应用层用
SELECT ... FOR UPDATE锁全表或锁范围——高并发下性能差,也容易死锁 - Redis 可做预占位:
SET short:aB3x long_url EX 300 NX,NX 保证原子性,失败则换 ID;但要注意缓存与 DB 不一致的风险
跳转时 302 还是 301?取决于你是否允许后期修改目标地址
HTTP 状态码选型直接影响浏览器缓存行为。用户点击短链接后,服务端查出原始 URL,然后发重定向响应。
- 用
302 Found:每次请求都走服务端,适合需要统计点击、A/B 测试、或后期可能改目标 URL 的场景 - 用
301 Moved Permanently:浏览器可能长期缓存跳转结果,下次直接跳,绕过你的服务——一旦目标 URL 改了,旧短链就永久失效 - Spring Boot 示例:用
ResponseEntity.status(HttpStatus.FOUND).header("Location", originalUrl).build()
真正难处理的是短码解析后的 URL 校验:空值、协议非法(如 javascript:)、超长、黑名单域名——这些不拦住,你的短链服务就成了 XSS 或钓鱼中转站。










