标准 API 接口文档
面向前端的 API 接口接入指南
占位符约定
本文档中「前端实例」基于 JavaScript(浏览器 fetch API)编写,「示例代码」基于 cURL 编写。
本文档使用 {花括号} 标记占位符,使用时请替换为实际值:
| 占位符 | 含义 | 示例 |
|---|---|---|
{你的域名} | 短链服务部署的域名 | s.example.com |
{su_你的Key} | 你的 API Key | su_aBcDeFgH1234 |
{长链接} / {目标长链接} | 要缩短的原始 URL | https://example.com/very/long/path |
{短链后缀} | 短链路径部分,1–4 位 | a1b2 |
{指定后缀} | 自定义的短链后缀 | my-link |
{完整短链地址} | 生成的完整短链 URL | https://s.example.com/a1b2 |
{ISO 8601 过期时间} | 链接过期时间,ISO 8601 格式 | 2026-05-20T12:00:00+08:00 |
{永久/临时短链当前数量} | 当前已有的短链数量 | 12 |
{永久/临时短链配额上限} | 配额上限值 | 9999 |
一、快速上手
所有标准接口均支持 CORS,可直接在浏览器端调用。认证通过 API Key 完成,Key 的传递方式取决于请求类型:
- POST 请求(创建、删除):Key 放在请求体 JSON 的
key字段 - GET 请求(查询列表、查询配额):Key 放在
X-Token请求头
二、API Key 说明
| Key 类型 | 有效期 | 使用次数 | 适用场景 |
|---|---|---|---|
| 常驻 Key | 7 天 | 不限 | 管理操作(增删查) |
| 一次性 Key | 永不过期(直到使用) | 仅 1 次,用后自动销毁 | 临时授权、前端嵌入 |
注意:
- Key 明文仅在生成时(
nurl -new)显示一次,后续无法通过 API 查询 - 一次性 Key 用后从池中移除,补充需手动执行
nurl -full
认证失败时,所有接口统一返回:
HTTP 406
{ "error": "密钥失效或不正确" }三、标准接口详情
1. 创建短链
POST /api/create
Content-Type: application/json{
"url": "{目标长链接}",
"ttl": 0,
"code": "{自定义短链后缀}",
"key": "{su_你的Key}"
}Prop
Type
TTL 常用换算:
| 时长 | 换算 | ttl 值 |
|---|---|---|
| 永久 | — | 0 |
| 30 分钟 | 30 × 60 | 1800 |
| 1 小时 | 60 × 60 | 3600 |
| 1 天 | 24 × 3600 | 86400 |
| 7 天 | 7 × 86400 | 604800 |
{
"short_url": "https://{你的域名}/{短链后缀}"
}{
"short_url": "https://{你的域名}/{短链后缀}",
"exp": "{ISO 8601 过期时间}"
}short_url 仅在此响应中出现一次,请妥善保存。
Prop
Type
| 状态码 | error 消息 | 原因 |
|---|---|---|
400 | 缺少目标链接 | url 字段缺失 |
400 | 目标链接无效 | URL 格式不合法 |
400 | TTL 超限 | ttl 超出范围 |
400 | 后缀格式错误 | code 格式不合法 |
400 | 保留字 | code 是系统保留字 |
406 | 缺少密钥 | key 字段缺失 |
406 | 密钥失效或不正确 | Key 无效、已过期或已使用 |
409 | 已占用 | 自定义 code 与已有短链冲突 |
429 | 已达上限 | 配额不足 |
430 | 数据不可访问:{文件名} | 数据文件权限错误 |
500 | 服务器内部错误 | 数据写入验证失败(v2.1 safe_write 保护) |
curl -X POST https://{你的域名}/api/create \
-H "Content-Type: application/json" \
-d '{"url":"{长链接}","ttl":0,"key":"{su_你的Key}"}'curl -X POST https://{你的域名}/api/create \
-H "Content-Type: application/json" \
-d '{"url":"{长链接}","ttl":0,"code":"{指定后缀}","key":"{su_你的Key}"}'curl -X POST https://{你的域名}/api/create \
-H "Content-Type: application/json" \
-d '{"url":"{长链接}","ttl":1800,"key":"{su_你的Key}"}'curl -X POST https://{你的域名}/api/create \
-H "Content-Type: application/json" \
-d '{"url":"{长链接}","ttl":1800,"code":"{指定后缀}","key":"{su_你的Key}"}'async function createShortUrl() {
const domain = document.getElementById('domain').value.trim();
const key = document.getElementById('key').value.trim();
const url = document.getElementById('url').value.trim();
const ttl = parseInt(document.getElementById('ttl').value, 10);
const code = document.getElementById('code').value.trim();
const res = await fetch(`https://${domain}/api/create`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ url, ttl, code, key }),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error);
return data; // { short_url, exp? }
}所有字段均由用户输入,对应页面元素 id:domain(短链域名)、key(API Key)、url(目标链接)、ttl(有效期下拉框)、code(自定义后缀)。TTL 可选值参考:永久 0、30 分钟 1800、1 小时 3600、1 天 86400、7 天 604800。
2. 查询短链列表
GET /api/list
X-Token: {su_你的Key}{
"permanent": [
{
"id": "{短链后缀}",
"url": "{目标长链接}",
"lurl": "{完整短链地址}",
"exp": "permanent"
}
],
"temporary": [
{
"id": "{短链后缀}",
"url": "{目标长链接}",
"lurl": "{完整短链地址}",
"exp": "{ISO 8601 过期时间}"
}
]
}返回的临时短链列表已自动过滤掉已过期的条目,无需客户端二次判断。
Prop
Type
| 状态码 | error 消息 | 原因 |
|---|---|---|
406 | 缺少密钥 | X-Token 头缺失 |
406 | 密钥失效或不正确 | Key 无效 |
430 | 数据不可访问:{文件名} | 数据文件权限错误 |
curl https://{你的域名}/api/list \
-H "X-Token: {su_你的Key}"async function listShortUrls() {
const domain = document.getElementById('domain').value.trim();
const key = document.getElementById('key').value.trim();
const res = await fetch(`https://${domain}/api/list`, {
headers: { 'X-Token': key },
});
const data = await res.json();
if (!res.ok) throw new Error(data.error);
return data; // { permanent: [...], temporary: [...] }
}GET 请求通过 X-Token 请求头传递 Key。对应页面元素 id:domain(短链域名)、key(API Key)。
3. 删除短链
POST /api/delete
Content-Type: application/json{
"code": "{短链后缀}",
"key": "{su_你的Key}"
}Prop
Type
{ "ok": true }| 状态码 | error 消息 | 原因 |
|---|---|---|
400 | 缺少短链后缀 | code 字段缺失 |
404 | 该短链不存在 | code 未找到 |
406 | 缺少密钥 | key 字段缺失 |
406 | 密钥失效或不正确 | Key 无效 |
430 | 数据不可访问:{文件名} | 数据文件权限错误 |
500 | 服务器内部错误 | 数据写入验证失败(v2.1 safe_write 保护) |
curl -X POST https://{你的域名}/api/delete \
-H "Content-Type: application/json" \
-d '{"code":"{短链后缀}","key":"{su_你的Key}"}'async function deleteShortUrl() {
const domain = document.getElementById('domain').value.trim();
const key = document.getElementById('key').value.trim();
const code = document.getElementById('code').value.trim();
const res = await fetch(`https://${domain}/api/delete`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ code, key }),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error);
return data; // { ok: true }
}POST 请求,Key 放在请求体中。对应页面元素 id:domain(短链域名)、key(API Key)、code(要删除的短链后缀)。
4. 查询配额状态
GET /api/stat
X-Token: {su_你的Key}{
"perm_count": {永久短链当前数量},
"temp_count": {临时短链当前数量},
"perm_limit": {永久短链配额上限},
"temp_limit": {临时短链配额上限}
}Prop
Type
| 状态码 | error 消息 | 原因 |
|---|---|---|
406 | 缺少密钥 | X-Token 头缺失 |
406 | 密钥失效或不正确 | Key 无效 |
430 | 数据不可访问:{文件名} | 数据文件权限错误 |
curl https://{你的域名}/api/stat \
-H "X-Token: {su_你的Key}"async function getStat() {
const domain = document.getElementById('domain').value.trim();
const key = document.getElementById('key').value.trim();
const res = await fetch(`https://${domain}/api/stat`, {
headers: { 'X-Token': key },
});
const data = await res.json();
if (!res.ok) throw new Error(data.error);
return data; // { perm_count, temp_count, perm_limit, temp_limit }
}GET 请求通过 X-Token 请求头传递 Key。对应页面元素 id:domain(短链域名)、key(API Key)。返回值中 perm_count / temp_count 为当前数量,perm_limit / temp_limit 为配额上限。
四、通用错误码
| 状态码 | 含义 |
|---|---|
400 | 请求参数缺失或格式不合法 |
404 | 资源不存在 |
406 | Key 缺失、无效、已过期或已使用 |
409 | 后缀冲突(已存在) |
429 | 配额已满 |
430 | 数据文件不可读写(权限未设置为 666 / 目录未设置为 777),响应体列出具体文件名 |
500 | 服务器内部错误 |
430 在所有接口中优先于认证检查返回。v1.10.1 起,响应体会列出具体不可访问的文件名(如 {"error":"数据不可访问:keys.json"})。如果收到 430,说明服务器 data/ 目录或内部文件权限配置有误,请检查目录权限是否为 777、文件权限是否为 666。
五、CORS 说明
CORS(Cross-Origin Resource Sharing,跨源资源共享)是一种浏览器安全机制,用于控制一个域名下的网页是否可以访问另一个域名下的资源。
默认情况下,浏览器会阻止网页向不同域名的服务器发送请求(同源策略)。例如你的前端页面部署在 https://app.example.com,而短链 API 部署在 https://s.yourdomain.com,浏览器会拦截这个跨域请求,除非服务器通过 CORS 响应头明确允许。
标准 API 已预配置 CORS 响应头,允许你指定的短链域名跨域访问:
Access-Control-Allow-Origin: https://s.yourdomain.com
Access-Control-Allow-Headers: Content-Type, X-Token
Access-Control-Allow-Methods: GET, POST, OPTIONSAccess-Control-Allow-Origin:允许发起跨域请求的域名,即你配置的短链域名Access-Control-Allow-Headers:允许前端发送的自定义请求头,包括Content-Type(POST 请求体格式)和X-Token(GET 请求认证)Access-Control-Allow-Methods:允许的 HTTP 方法
浏览器在发送实际请求前,会先发送一个 OPTIONS 预检请求(Preflight),服务器返回 204 No Content 并附带上述响应头。浏览器检查通过后才会发送真正的业务请求。
前端无需做任何额外配置,直接使用 fetch / XMLHttpRequest 调用即可,浏览器会自动处理 CORS 流程。如果遇到跨域错误,请检查:
- 前端页面域名是否与 CORS 配置中的域名一致
- 是否使用了未在
Access-Control-Allow-Headers中声明的请求头
无头接口不设置 CORS,仅供后端调用。
六、前端集成
1. 基础封装
Key 放在请求体中,用于创建和删除操作:
const API_BASE = 'https://{你的域名}/api';
async function apiPost(endpoint, body) {
const res = await fetch(`${API_BASE}${endpoint}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
});
const data = await res.json();
if (!res.ok) throw { status: res.status, message: data.error };
return data;
}Key 放在 X-Token 请求头中,用于查询操作:
const API_BASE = 'https://{你的域名}/api';
async function apiGet(endpoint, token) {
const res = await fetch(`${API_BASE}${endpoint}`, {
headers: { 'X-Token': token },
});
const data = await res.json();
if (!res.ok) throw { status: res.status, message: data.error };
return data;
}2. 调用示例
const KEY = '{su_你的Key}';
// 创建永久短链
const { short_url } = await apiPost('/create', {
url: '{长链接}',
ttl: 0,
key: KEY,
});
console.log(short_url); // "https://{你的域名}/{短链后缀}"
// 创建 30 分钟临时短链
const temp = await apiPost('/create', {
url: '{长链接}',
ttl: 30 * 60,
key: KEY,
});
console.log(temp.short_url); // "https://{你的域名}/{短链后缀}"
console.log(temp.exp); // "{ISO 8601 过期时间}"
// 删除短链
await apiPost('/delete', { code: '{短链后缀}', key: KEY });
// 查询所有短链
const list = await apiGet('/list', KEY);
// 查询配额
const stat = await apiGet('/stat', KEY);
console.log(`永久短链:${stat.perm_count} / ${stat.perm_limit}`);
console.log(`临时短链:${stat.temp_count} / ${stat.temp_limit}`);