圣堂之魂
开发指南

标准 API 接口文档

面向前端的 API 接口接入指南


占位符约定

本文档中「前端实例」基于 JavaScript(浏览器 fetch API)编写,「示例代码」基于 cURL 编写。

本文档使用 {花括号} 标记占位符,使用时请替换为实际值:

占位符含义示例
{你的域名}短链服务部署的域名s.example.com
{su_你的Key}你的 API Keysu_aBcDeFgH1234
{长链接} / {目标长链接}要缩短的原始 URLhttps://example.com/very/long/path
{短链后缀}短链路径部分,1–4 位a1b2
{指定后缀}自定义的短链后缀my-link
{完整短链地址}生成的完整短链 URLhttps://s.example.com/a1b2
{ISO 8601 过期时间}链接过期时间,ISO 8601 格式2026-05-20T12:00:00+08:00
{永久/临时短链当前数量}当前已有的短链数量12
{永久/临时短链配额上限}配额上限值9999

一、快速上手

所有标准接口均支持 CORS,可直接在浏览器端调用。认证通过 API Key 完成,Key 的传递方式取决于请求类型:

  1. POST 请求(创建、删除):Key 放在请求体 JSON 的 key 字段
  2. GET 请求(查询列表、查询配额):Key 放在 X-Token 请求头

二、API Key 说明

Key 类型有效期使用次数适用场景
常驻 Key7 天不限管理操作(增删查)
一次性 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 × 601800
1 小时60 × 603600
1 天24 × 360086400
7 天7 × 86400604800
永久短链
{
  "short_url": "https://{你的域名}/{短链后缀}"
}
临时短链
{
  "short_url": "https://{你的域名}/{短链后缀}",
  "exp": "{ISO 8601 过期时间}"
}

short_url 仅在此响应中出现一次,请妥善保存。

Prop

Type

状态码error 消息原因
400缺少目标链接url 字段缺失
400目标链接无效URL 格式不合法
400TTL 超限ttl 超出范围
400后缀格式错误code 格式不合法
400保留字code 是系统保留字
406缺少密钥key 字段缺失
406密钥失效或不正确Key 无效、已过期或已使用
409已占用自定义 code 与已有短链冲突
429已达上限配额不足
430数据不可访问:{文件名}数据文件权限错误
500服务器内部错误数据写入验证失败(v2.1 safe_write 保护)
永久短链(自动生成 code)
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}"}'
30 分钟临时短链(自动生成 code)
curl -X POST https://{你的域名}/api/create \
  -H "Content-Type: application/json" \
  -d '{"url":"{长链接}","ttl":1800,"key":"{su_你的Key}"}'
30 分钟自定义后缀临时短链
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? }
}

所有字段均由用户输入,对应页面元素 iddomain(短链域名)、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。对应页面元素 iddomain(短链域名)、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 放在请求体中。对应页面元素 iddomain(短链域名)、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。对应页面元素 iddomain(短链域名)、key(API Key)。返回值中 perm_count / temp_count 为当前数量,perm_limit / temp_limit 为配额上限。


四、通用错误码

状态码含义
400请求参数缺失或格式不合法
404资源不存在
406Key 缺失、无效、已过期或已使用
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, OPTIONS
  • Access-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 流程。如果遇到跨域错误,请检查:

  1. 前端页面域名是否与 CORS 配置中的域名一致
  2. 是否使用了未在 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}`);

本页目录