LSink 短链接开放 API 开发者文档

版本: v1.0 | 更新: 2026-08-13 | 服务: https://lsink.tesmusic.top

LSink 提供企业级短链接生成服务,其他系统可通过开放 API 接入,将长 URL 转换为短链接并嵌入自己的业务系统。


一、接入流程(购买服务)

支付框架已上线(订单/回调/额度发放),当前为模拟支付渠道;微信/支付宝真实渠道接入中(实现 PaymentChannel 接口即可)。

  1. 购买开通:联系管理员(账号 Lemon)开通企业服务,获取客户标识 X-Api-Key 与额度套餐;也可在控制台自助下单(模拟支付)
  2. 生成密钥对:本地生成 RSA-2048 密钥对(ssh-keygen -t rsa -b 2048 -m PEM 或项目 KeyGenTool),私钥自留
  3. 上传公钥:将公钥 Base64 提供给管理员,注册到平台客户密钥库(公钥指纹线下核验)
  4. 联调上线:按本文档签名规则接入,调用 /api/urls 验证通过后上线

额度按"短链接条数"计费,生成成功即扣减 1 条,可在额度接口查询余量。


二、基础信息

Base URL https://lsink.tesmusic.top
数据格式 JSON (UTF-8)
请求签名 RSA-2048 (SHA256withRSA),见第四节
时间戳容忍 ±5 分钟
限流 生成接口 10 次/秒/客户,统计 20 次/分钟,二维码 30 次/分钟

三、接口总览

方法 路径 鉴权 说明
POST /api/urls RSA 签名 生成短链接(核心)
GET /{code} 302 跳转到长 URL
GET /api/qr/{code} 获取短链接二维码 PNG
GET /api/stats/{code} 点击统计(总点击 + 7 天趋势)
GET /api/status 平台状态(池余量、缓存命中率)
GET /actuator/health 健康检查

四、签名鉴权(必读,两端必须逐字节一致)

4.1 请求头

所有写接口(POST /api/urls)必须携带 4 个请求头:

请求头 说明
X-Api-Key 客户标识(购买时分配)
X-Timestamp 当前毫秒级时间戳,与服务器时间差超过 ±5 分钟拒绝
X-Nonce 随机字符串(UUID 即可),同一 nonce 10 分钟内不可重复使用(防重放)
X-Sign RSA-SHA256 签名(Base64),见下

4.2 签名规则

  1. 请求体 JSON 的全部字段 + X-Timestamp + X-Nonce,值转字符串
  2. 按 key 字典序(UTF-8 字节序)排序
  3. 拼成 key=value,value 做 form-urlencoded 编码(与 Java URLEncoder 一致):
  4. 字母、数字和 - _ . * 不转义
  5. 空格 → +
  6. 其他字符 → %XX(UTF-8 字节,大写十六进制)
  7. 各项用 & 连接,得到规范串
  8. 用客户私钥对规范串做 SHA256withRSA 签名,Base64 编码后放入 X-Sign

⚠️ 注意:不是 RFC 3986(%20)编码!非 Java 客户端必须按本表实现,否则验签必然失败。

4.3 签名示例

请求体 {"longUrl":"https://a.com/x"}X-Timestamp=1700000000123X-Nonce=n1

规范串: longUrl=https%3A%2F%2Fa.com%2Fx&nonce=n1&ts=1700000000123
签名:   Base64(SHA256withRSA(规范串, 私钥))

4.4 常见失败原因

错误 原因
缺少签名头 4 个请求头未带全
未知客户 X-Api-Key 未注册
请求已过期或时间戳非法 本地时间与服务器差超 5 分钟(NTP 同步)
验签失败 规范串拼错 / 编码不一致 / 请求被篡改
重放攻击 nonce 已被使用过

五、接口详情

5.1 生成短链接 POST /api/urls(需签名)

生成一条短链接,返回短码与完整短链地址。

请求体:

{
  "longUrl": "https://www.example.com/path?query=1",
  "customCode": "mycode"      // 可选,自定义短码,1-20 位 [A-Za-z0-9-_]
}

响应 200:

{
  "shortUrl": "https://lsink.tesmusic.top/mycode",
  "code": "mycode"
}

错误响应:

状态码 场景
400 参数不合法(longUrl 为空/过长、自定义短码被占用或与系统池冲突)
401 签名校验失败(见 4.4)
403 额度不足,需购买扩容
429 触发限流
503 短码池耗尽(平台故障,重试即可)

5.2 短链跳转 GET /{code}(公开)

访问短链时自动 302 重定向到长 URL。响应带 Cache-Control: public, s-maxage=60,CDN 可缓存 60 秒。

5.3 二维码 GET /api/qr/{code}(公开)

返回短链对应的二维码 PNG 图片,可直接 <img src="https://lsink.tesmusic.top/api/qr/abc123"> 嵌入页面。

5.4 点击统计 GET /api/stats/{code}(公开)

{
  "code": "abc123",
  "total": 100,
  "daily": [
    {"date": "2026-08-07", "clicks": 10},
    {"date": "2026-08-13", "clicks": 15}
  ]
}

5.5 平台状态 GET /api/status(公开)

{
  "poolRemaining": 90000,
  "cacheHitRate": 0.87
}

5.6 健康检查 GET /actuator/health(公开)

{"status": "UP"}

六、代码示例

6.1 curl

# 1. 拼规范串(按 4.2 规则)
# longUrl=https%3A%2F%2Fa.com%2Fx&nonce=<nonce>&ts=<ts>
# 2. 签名(openssl,私钥为 PEM 格式)
SIGN=$(printf '%s' "longUrl=https%3A%2F%2Fa.com%2Fx&nonce=$NONCE&ts=$TS" \
  | openssl dgst -sha256 -sign private.pem -binary | base64 -w0)

curl -X POST https://lsink.tesmusic.top/api/urls \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: <your-api-key>" \
  -H "X-Timestamp: $TS" \
  -H "X-Nonce: $NONCE" \
  -H "X-Sign: $SIGN" \
  -d '{"longUrl":"https://a.com/x"}'

6.2 Python

import base64, hashlib, json, time, uuid
from urllib.parse import quote
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
import requests

PRIVATE_KEY_PATH = "private.pem"
API_KEY = "your-api-key"
BASE = "https://lsink.tesmusic.top"

def encode(v: str) -> str:
    # form-urlencoded:空格 -> '+'
    return quote(v, safe="-_.*").replace("%20", "+")

def sign(long_url: str) -> dict:
    ts = str(int(time.time() * 1000))
    nonce = str(uuid.uuid4())
    params = {"longUrl": long_url, "ts": ts, "nonce": nonce}
    canonical = "&".join(f"{k}={encode(params[k])}" for k in sorted(params))
    with open(PRIVATE_KEY_PATH, "rb") as f:
        key = serialization.load_pem_private_key(f.read(), password=None)
    sig = base64.b64encode(key.sign(
        canonical.encode(), padding.PKCS1v15(), hashes.SHA256())).decode()
    return {"X-Api-Key": API_KEY, "X-Timestamp": ts,
            "X-Nonce": nonce, "X-Sign": sig, "canonical": canonical}

def create_short_url(long_url: str) -> dict:
    h = sign(long_url)
    r = requests.post(f"{BASE}/api/urls", json={"longUrl": long_url}, headers=h)
    return r.json()

6.3 Java(官方 KeyGenTool 一键演示)

# 生成密钥对(公钥自动上传注册 + 打印私钥)
java -jar lsink.jar --keygen
# 运行签名调用演示(正常 200 / 篡改 401 / 重放 401)
java -jar lsink.jar --client-demo

七、错误码汇总

状态码 含义 处理建议
200 成功 -
302 跳转(GET /{code}) -
400 请求参数错误 检查 longUrl / customCode
401 鉴权失败 按 4.4 排查签名
403 额度不足 联系管理员购买
404 短码不存在 检查 code
429 触发限流 降频重试
500 服务器错误 联系管理员
503 服务暂不可用 稍后重试

八、常见问题

Q: 短链有效期多久? 当前演示配置 TTL 60 秒,生产配置可为 2 年。到期后自动回收,短码可被重新分配。

Q: 支持自定义短码吗? 支持,customCode 1-20 位 [A-Za-z0-9-_],与系统预生成池隔离。已被使用会返回 400。

Q: 能统计每个短链的点击量吗? 可以,GET /api/stats/{code} 返回总点击与 7 天趋势。

Q: 如何接入自己的域名? 支持,联系管理员配置域名绑定(CDN 缓存 60 秒)。

Q: 额度用完了怎么办? 403 提示额度不足。控制台可自助购买套餐(当前模拟支付渠道),或联系管理员(账号 Lemon)人工扩容。


LSink · 短链接平台 · 技术支持:联系 Lemon