Skip to content
语言: 中文(简体)

开发者 API

速率限制:所有限额和响应头

更新于 2026年11月1日 阅读约 5 分钟

LinkHarbor API 每分钟允许多少次请求、单个请求可以有多大、如何读取响应头,以及如何正确处理 429。

为了让 API 对所有人都保持快速,LinkHarbor 会限制每分钟的请求数。这些限制与套餐无关,也没有每月的 API 调用配额。本文列出所有限制,并说明你的代码如何妥善处理它们。

请求如何计数

  • 每个请求都恰好归入一个桶(bucket),例如已认证的请求归入 user,换取令牌归入 token
  • 按整分钟(UTC)计数;每到新的一分钟,计数器从零重新开始
  • 根据桶的不同,API 按工作区、按人、按连接或按 IP 地址计数
  • 在令牌、权限范围或结构校验阶段就失败的请求(401、403 insufficient_scope、400、结构校验产生的 422 validation_failed)不计入;之后才出现的错误(例如 403 feature_not_available)会计入

所有限制

桶(X-RateLimit-Bucket)限制计数单位适用于
user每分钟 600 次API 密钥的令牌按工作区计(工作区的所有密钥和 AI 工具合计);控制台登录按人计所有没有单独桶的、对 /v1 的已认证请求
token每分钟 30 次IP 地址POST /v1/token
public每分钟 120 次IP 地址无需身份验证的 API 请求,例如 GET /v1/plans 和 GET /v1/pages/available
callback每分钟 120 次IP 地址POST /v1/callbacks/sale
internal每分钟 120 次IP 地址“Custom (API)”集成的接入 URL(POST /v1/ingest/{id})
mcp每分钟 120 次AI 连接(访问令牌)位于 /mcp 的 MCP 服务器
oauth每分钟 300 次IP 地址AI 助手的 OAuth 登录和发现
auth每分钟 30 次IP 地址登录、注册、重置密码(控制台和应用)
refresh每分钟 120 次IP 地址延长控制台会话
discover每分钟 60 次按人计,未登录时按 IP 地址应用中的“发现”
subs_read每分钟 120 次按人计,未登录时按 IP 地址读取你关注的页面(应用)
subs_write每分钟 20 次按人计,未登录时按 IP 地址更改你关注的页面(应用)

每个工作区共用一份额度

同一工作区中所有 API 密钥的令牌共享每分钟 600 次请求,无论你创建了多少个密钥。已连接 AI 助手的工具也计入其中,因为它们在内部调用 API。所以增加密钥并不会提高上限。如果大量负载分散在多个程序中,请按这份共享额度来规划。

响应头

X-RateLimit-Limit
该桶每分钟的上限,例如 600。
X-RateLimit-Remaining
当前这一分钟还剩多少次请求。
X-RateLimit-Bucket
请求归入的桶,例如 user。
Retry-After
仅在 429 rate_limited 时出现:距下一分钟开始还有多少秒。出现 api_key_locked 时,等待时间在 details.retry_after_sec 中。

达到上限时

达到上限后,API 会返回 HTTP 429 和以下响应体。message 的文本使用账户语言(参见 API 错误格式和错误代码),此处为英语。请以错误代码 rate_limited 为准:

429 响应
HTTP/1.1 429 Too Many Requests
Retry-After: 37
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 0
X-RateLimit-Bucket: user

{ "error": "rate_limited", "message": "Too many requests. Please try again in a moment.", "retry_after_sec": 37 }
  1. 读取 Retry-After 或 retry_after_sec
  2. 至少等待这么多秒,再加上一点随机时间,避免所有进程在同一时刻重新开始
  3. 最多重试几次
  4. 如果一直收到 429,请把工作分散到更长的时间里
Node.js:缓存令牌并处理 429
const BASE = 'https://dock.at-harbor.com';
let cached = null; // { token, expiresAt }

async function getToken() {
  if (cached && Date.now() < cached.expiresAt - 60_000) return cached.token;
  const res = await fetch(BASE + '/v1/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      key_id: process.env.LH_KEY_ID,
      key_secret: process.env.LH_KEY_SECRET,
    }),
  });
  if (!res.ok) throw new Error('Token exchange failed: HTTP ' + res.status);
  const data = await res.json();
  cached = { token: data.token, expiresAt: Date.now() + data.expires_in * 1000 };
  return cached.token;
}

async function lh(method, path, body, attempt = 0) {
  const headers = { Authorization: 'Bearer ' + (await getToken()) };
  if (body !== undefined) headers['Content-Type'] = 'application/json';

  const res = await fetch(BASE + path, {
    method,
    headers,
    body: body === undefined ? undefined : JSON.stringify(body),
  });

  if (res.status === 429 && attempt < 3) {
    const wait = Number(res.headers.get('Retry-After') ?? 5);
    await new Promise((r) => setTimeout(r, (wait + Math.random() * 2) * 1000));
    return lh(method, path, body, attempt + 1);
  }
  if (res.status === 401 && attempt === 0) {
    cached = null; // 令牌已过期,用新令牌再试一次
    return lh(method, path, body, attempt + 1);
  }
  const data = await res.json().catch(() => null);
  if (!res.ok) throw new Error((data && data.error) + ' (HTTP ' + res.status + ')');
  return data;
}

// 示例:const { items } = await lh('GET', '/v1/pages');

处理大量数据的建议

  • 缓存令牌,只在它 15 分钟后过期前不久再续期
  • 留意 X-RateLimit-Remaining,余量变少时放慢速度
  • 逐个发送请求,而不是同时开几十个并行连接
  • 一次性加载列表并在本地筛选,而不是逐个查询每个页面
  • 把大型同步分散到几分钟内完成
  • 5xx 错误以逐渐延长的间隔重试,4xx 错误则不要重试

其他限制

项目限制响应
登录失败同一邮箱地址和 IP 失败 5、10 和 20 次后分别锁定 60 秒、5 分钟、30 分钟429 account_locked
表单提交每个 IP 地址每小时 10 次,所有表单合计429 form_rate_limited

换取令牌时的失败尝试会暂时锁定密钥和 IP,参见 API 密钥和访问令牌。推送通知只能在控制台中发送,它们的限制请参阅关注者和推送通知。

套餐的内容限额(页面、链接、模块、短链接等)不是速率限制,而是固定上限。它们列在套餐对比中。

请求大小

每个请求体在 API 读取之前都会先测量大小。允许的大小取决于端点:

端点最大请求体
登录、注册以及 /v1/auth 下其他无需身份验证的调用,POST /v1/token,POST /v1/oauth/exchange,/oauth 下供 AI 助手使用的 OAuth 端点及其授权,POST /v1/ingest/{id},“支持”模块的结账,应用的订阅相关调用(关注、收藏夹、推送设备),切换工作区,POST /v1/auth/logout-all,删除账户,设置双重验证,接受邀请,启用推荐计划,以及连接集成时的返回步骤64 KB
所有其他 JSON 端点,包括在页面上提交表单1 MB
POST /v1/webhooks/{id}/verify-signature 和位于 /mcp 的 MCP 服务器2 MB
文件上传(POST /v1/assets 和 POST /v1/pages/{id}/uploads,multipart/form-data)整个请求 11 MB,文件本身最多 10 MB

如果请求体更大,API 会返回 413 request_too_large;details.max_bytes 和 details.max_kb 给出上限。上传的文件过大会导致 413 payload_too_large。没有请求体的端点(例如 DELETE 调用)不接受请求体,或只接受 {}。

413 响应
HTTP/1.1 413 Payload Too Large

{ "error": "request_too_large", "message": "…", "details": { "max_bytes": 65536, "max_kb": 64 }, "request_id": "…" }

请求体内部也有限制:每段文本都有最大长度,每个列表都有最大条目数,未知字段会被拒绝。具体数值在 API 参考中按端点列出。违反时会返回 422 validation_failed,details 会指出字段、规则和上限。请求的路径和查询字符串加起来最多 16 KB。

没找到答案?

告诉我们你需要什么,我们的客服团队会亲自帮你。

联系客服