短链接
受众:开发者 摘要:短链接模块第一阶段能力:短链管理、公开解析、浏览器跳转、访问明细、地域统计、访问趋势、访问导出和权限。
spring-open-module-short-link 提供短链接业务能力。第一阶段已落地短链接底座、访问明细、地域 / 来源 / 设备聚合、按天访问趋势、访问明细导出、安全域名拦截、跳转风险提示、风险提示访问通知事件源和公开访问限流,后续再扩展渠道投放。
什么时候使用
适合这些场景:
- 运营活动短链接。
- App / PC / Admin 分享入口。
- 短信、邮件、通知中的短链跳转。
- 渠道投放和访问统计。
不适合把它当作文件存储、支付回调或开放平台签名入口。短链接只负责解析和跳转,不负责承载业务安全授权。
模块边界
| 项 | 值 |
|---|---|
| Maven 模块 | spring-open-module-short-link |
| API 前缀 | /api/v1/short-links/** |
| 配置前缀 | spring.open.short-link.* |
| Java 包名 | com.springopen.module.shortlink |
| 数据表 | short_link、short_link_visit |
| 权限码前缀 | short-link:* |
应用默认引入该模块,裸模块可通过配置关闭:
spring:
open:
short-link:
enabled: true
security:
blocked-hosts:
- risk.example.com
warning-hosts:
- suspicious.example.com
block-local-hosts: false
block-private-ip-hosts: false
rate-limit:
enabled: true
max-attempts: 120
window: 1m数据表
第一阶段新增两张表:
| 表 | 说明 |
|---|---|
short_link | 短链接主体,保存短码、目标 URL、状态、过期时间、访问次数和扩展信息 |
short_link_visit | 短链接访问明细,保存访问短码、Referer、来源域名、User-Agent、IP、地域、设备、浏览器、系统和访问时间 |
短码 code 全局唯一,只允许字母、数字、下划线和中划线,长度 3 到 64。短码一旦创建会长期占用,逻辑删除后也不会重新分配给其他短链接,避免历史链接被误跳转。
后台管理 API
后台接口需要登录并校验权限:
| 方法 | 路径 | 权限 | 说明 |
|---|---|---|---|
GET | /api/v1/admin/short-links/short-links | short-link:short-link:view | 分页查询短链接 |
GET | /api/v1/admin/short-links/short-links/statistics | short-link:short-link:view | 查询短链接统计总览 |
GET | /api/v1/admin/short-links/short-links/{id} | short-link:short-link:view | 查看短链接详情 |
GET | /api/v1/admin/short-links/short-links/{id}/visits | short-link:short-link:view | 分页查询短链接访问明细 |
GET | /api/v1/admin/short-links/short-links/{id}/visits/export | short-link:short-link:view | 导出短链接访问明细 CSV |
GET | /api/v1/admin/short-links/short-links/{id}/visit-statistics | short-link:short-link:view | 查询短链接来源 / 设备 / 浏览器聚合 |
GET | /api/v1/admin/short-links/short-links/{id}/visit-trend | short-link:short-link:view | 查询短链接按天访问趋势,默认近 14 天,最大 90 天 |
POST | /api/v1/admin/short-links/short-links | short-link:short-link:create | 创建短链接 |
POST | /api/v1/admin/short-links/short-links/import | short-link:short-link:create | 导入短链接 CSV |
PUT | /api/v1/admin/short-links/short-links/{id} | short-link:short-link:update | 修改短链接 |
DELETE | /api/v1/admin/short-links/short-links/{id} | short-link:short-link:delete | 删除短链接 |
DELETE | /api/v1/admin/short-links/short-links | short-link:short-link:delete | 批量删除短链接 |
统计总览返回短链总数、启用数、停用数、过期数、带密码数、累计访问量和 Top 访问短链。访问明细统计返回总明细数、独立 IP、最近访问时间、Top 来源域名、Top 地域、Top 设备和 Top 浏览器。访问趋势按连续日期返回访问次数和独立 IP 数,便于 Admin 在访问明细抽屉展示近 14 天趋势。访问明细导出返回 text/csv;charset=UTF-8 附件,字段包含短码、访问时间、IP、地域、来源域名、Referer、设备、浏览器、系统和 User-Agent,按最近访问优先排序。
创建请求示例:
{
"code": "example",
"title": "项目官网",
"targetUrl": "https://example.com",
"description": "活动入口",
"status": 1,
"expiresAt": "2026-12-31T23:59:59",
"accessPassword": "123456",
"utmSource": "newsletter"
}code 可不传,后端会生成 8 位短码。targetUrl 只允许 http / https,且会按 spring.open.short-link.security.blocked-hosts 拦截风险域名;配置主域名时会同时拦截其子域名。 如果目标域名需要保留但不适合直接 302,可配置 spring.open.short-link.security.warning-hosts,浏览器访问 /s/{code} 时会在正常解析、密码校验和访问记录后展示风险确认页,由用户点击后再离开当前站点;确认页渲染前会发布 short-link.security.warning-visit 通知规则事件源,运营可在 Notification 通知规则中配置站内信 / 邮件接收人。 公开短链面向外部用户时,建议按部署场景打开 spring.open.short-link.security.block-local-hosts 和 spring.open.short-link.security.block-private-ip-hosts。前者禁止 localhost / *.localhost 目标,后者禁止内网、回环、链路本地、未指定地址、IPv6 ULA 和 CGNAT 等裸 IP 目标;两个开关默认关闭, 避免开发 / 预览环境误伤本机调试链接。开关打开后,后台保存和公开解析都会执行同一套检查,历史短链也会被运行期策略即时拦截。 utmSource、utmMedium、utmCampaign 会在公开解析和浏览器跳转成功时分别追加为 utm_source、utm_medium、utm_campaign 查询参数;目标 URL 已有同名参数时保留原值, 原有 query 和 fragment 会继续保留。
批量创建适合运营活动一次生成多条共享目标地址的短链:
POST /api/v1/admin/short-links/short-links/batch{
"titlePrefix": "春季活动",
"targetUrl": "https://example.com/spring",
"codePrefix": "spring",
"count": 10,
"status": 1,
"utmSource": "admin",
"utmMedium": "campaign",
"utmCampaign": "spring-sale"
}count 范围为 1 到 100。传入 codePrefix 时,后端生成 spring-001、spring-002 这类有序短码;不传时由服务端逐条生成随机短码。批量创建和单条创建使用同一套 URL、 风险域名、短码唯一性和密码规则,任一条失败会回滚整批创建。
如果每条短链的目标地址、短码或 UTM 参数都不同,可使用 CSV 导入:
POST /api/v1/admin/short-links/short-links/import{
"csvContent": "code,title,targetUrl,description,status,expiresAt,accessPassword,utmSource,utmMedium,utmCampaign,extraJson\nspring-a,春季活动 A,https://example.com/a,活动入口,1,2026-12-31T23:59:59,123456,newsletter,email,spring-sale,{\"source\":\"csv\"}\nspring-b,春季活动 B,https://example.com/b"
}CSV 首行必须是表头,必填列为 title 和 targetUrl;可选列包括 code、description、 status、expiresAt、accessPassword、utmSource、utmMedium、utmCampaign 和 extraJson。表头兼容 targetUrl / target_url 这类大小写或分隔符差异。单次最多导入 100 行,任一行短码冲突、URL 校验失败或风险域名命中都会回滚整批导入。
修改短链接时,访问密码采用显式动作,避免表单未填写时误清空旧密码:
accessPasswordAction | 说明 |
|---|---|
keep 或不传 | 保持原密码 |
change | 使用本次 accessPassword 修改密码 |
clear | 清空访问密码 |
公开解析与跳转
| 方法 | 路径 | 说明 |
|---|---|---|
GET | /api/v1/short-links/short-links/{code} | 返回无密码短链接解析结果,适合 App / PC 自行处理跳转;可选 region 查询参数记录业务地域 |
POST | /api/v1/short-links/short-links/{code}/resolve | 解析带密码短链接,请求体提交 accessPassword,避免密码出现在 URL 和访问日志;可选 region 查询参数记录业务地域 |
GET | /s/{code} | 浏览器跳转到目标 URL;可选 region 查询参数记录业务地域;命中 warning-hosts 时先展示风险确认页 |
POST | /s/{code} | 浏览器密码页提交访问密码,校验成功后跳转;密码页会保留 region 隐藏字段;命中 warning-hosts 时先展示风险确认页 |
公开解析返回:
{
"code": "200",
"message": "成功",
"data": {
"code": "example",
"title": "项目官网",
"targetUrl": "https://example.com",
"expired": false,
"passwordRequired": false
}
}如果短链已禁用、过期、密码错误或目标域名命中黑名单,接口会返回统一 Result 业务错误。 App / PC 建议使用 POST /resolve 验证带密码短链,再由前端自行跳转;浏览器直接访问 /s/{code} 时, 带密码短链会返回轻量密码页,并通过 POST /s/{code} 提交密码,避免密码进入 URL、浏览器历史和访问日志。
访问次数由后端原子递增,避免高并发访问时统计丢失。公开解析和浏览器跳转成功后会写入 short_link_visit,记录 Referer、来源域名、IP、地域、User-Agent、设备、浏览器和系统;密码缺失、密码错误、禁用、过期或风险域名拦截不会写入访问明细。命中 warning-hosts 的浏览器访问会先展示风险确认页,并把已解析后的目标地址作为继续访问入口,不再二次调用短链解析,避免重复计数;同时发布 short-link.security.warning-visit,payload 携带短码、目标地址、目标域名、区域、来源 IP、Referer 和 User-Agent。region 是业务自定义地域编码,例如 CN-ZJ、CN-SH 或渠道系统传入的区域标识;为空时后台地域聚合归为“未知”。后台保存的 UTM 字段只影响公开返回和 302 目标 URL,不改变后台列表中的原始目标地址。
公开解析 API 和浏览器 /s/{code} 入口会复用 Rate Limit starter 做防刷限流。默认按“短码 + 访问 IP”维度在 1 分钟窗口内允许 120 次访问,限流 key 会对短码和 IP 做 SHA-256 哈希,避免在底层存储中直接暴露访问目标和来源。可通过 spring.open.short-link.security.rate-limit.* 调整开关、窗口、阈值、模块 key 前缀和指定 store;关闭 Rate Limit starter 或关闭该配置时退化为不限流。公开 API 超限时返回 429 统一 Result 和 Retry-After,浏览器入口超限时返回 429 HTML 提示页。
spring.open.short-link.enabled、安全域名和公开访问限流配置已由 ShortLinkServiceProvider 声明到 lifecycle 配置 schema,后台配置中心可发现这些键;未接入配置中心的部署仍可通过 application.yml / 环境变量配置。
机制说明
短链接模块的核心规则集中在 ShortLinkService,后台管理、公开解析和浏览器 302 跳转都复用同一套校验。
处理链路:
- 后台保存时规范化短码和目标 URL;短码只允许字母、数字、下划线和中划线,目标 URL 只允许
http/https。 - 如果没有传短码,后端生成 8 位短码,并在写入前检查唯一性。
- 批量创建时由后端按标题前缀、短码前缀和序号派生每条短链,并在同一事务内写入。
- CSV 导入先完整解析表头和所有数据行,再复用单条保存规则逐条创建;任一行失败会回滚整批导入。
- 后台统计总览基于
short_link当前数据聚合;访问明细基于short_link_visit分页展示,并按来源域名、地域、设备、浏览器和日期趋势聚合。 - 修改访问密码必须显式传
accessPasswordAction:keep保持、change修改、clear清空,避免后台表单空值误清空旧密码。 - 保存和公开解析都会检查
security.blocked-hosts;命中风险域名的短链不能创建,也不能继续跳转;浏览器跳转命中security.warning-hosts时会展示风险确认页。 security.block-local-hosts/security.block-private-ip-hosts开启后会额外禁止本机主机名或内网裸 IP 目标,避免公开短链被用作内网探测入口。- 公开解析 API 和浏览器
/s/{code}在进入业务解析前先按短码 + IP 消耗限流桶;超限时不调用解析 Service,不增加访问次数,也不写访问明细。 - 公开解析时先按短码查候选,再在 Java 内做精确匹配,兼容数据库默认大小写不敏感 collation。
- 解析成功后使用数据库原子自增访问次数,更新最后访问时间,并记录访问明细。
- 后台 UTM 字段在公开解析成功后追加到目标 URL;若目标 URL 已存在同名
utm_*参数,则不覆盖原值。 - 浏览器
/s/{code}对无密码短链直接 302;带密码短链返回密码页,POST /s/{code}校验后再 302。
短链接只负责“解析 + 跳转 + 基础统计”。登录态、支付授权、文件访问签名和业务权限不要放在短链接里实现。
权限与菜单
迁移会写入:
| 资源 | code |
|---|---|
| 菜单 | short-link |
| 菜单 | short-link:short-link |
| 查看 | short-link:short-link:view |
| 创建 | short-link:short-link:create |
| 修改 | short-link:short-link:update |
| 删除 | short-link:short-link:delete |
默认授予 super-admin 角色。
后续规划
第一阶段只做短链核心闭环。后续增强按独立任务推进:
- 访问统计:已支持访问明细、独立 IP、来源域名、地域、浏览器、设备聚合、按天趋势和 CSV 导出。
- Admin 报表:已支持总览指标、Top 访问短链、单条短链访问明细抽屉、地域视图和访问明细导出。
- 安全检测:黑名单域名已支持配置拦截,浏览器带密码跳转页、跳转风险提示、风险提示访问通知事件源和公开访问防刷限流已支持。
- 批量生成:Admin 已支持按共享目标地址、标题前缀、可选短码前缀和 UTM 参数批量创建,也支持 CSV 导入不同目标地址的多条短链。
- UTM 模板:已支持公开解析和浏览器跳转统一追加来源参数,避免前端重复拼接。
活码 / 动态二维码不放在短链接模块,使用独立 活码 模块承载。