Sink REST API 实战指南:OpenAPI 交互文档、Bearer Token 鉴权、CORS 与全部端点深度解析

📅 发布时间:2026/9/16 11:01:20
Sink REST API 实战指南:OpenAPI 交互文档、Bearer Token 鉴权、CORS 与全部端点深度解析
Sink REST API 实战指南OpenAPI 交互文档、Bearer Token 鉴权、CORS 与全部端点深度解析【免费下载链接】Sink⚡ A Simple / Speedy / Secure Link Shortener with Analytics, 100% run on Cloudflare.项目地址: https://gitcode.com/GitHub_Trending/si/SinkSink 是一个 100% 运行在 Cloudflare 上的短链接服务其 REST API 是连接自建实例与脚本、浏览器扩展、第三方应用的唯一入口。本文基于 docs/api/index.md 展开完整覆盖交互文档入口、认证机制、CORS 开关与端点分组并结合服务端中间件与路由源码server/middleware/2.auth.ts、server/middleware/3.link-store-gate.ts、nuxt.config.ts逐项验证实际行为读完即可独立通过 HTTP 接口完成短链的创建、查询、导入导出与备份操作。交互文档三个开箱即用的 OpenAPI 入口每个 Sink 实例都会在构建时自动生成 API 文档无需额外部署。替换为你的域名后有三个入口路径用途https://your-domain/_docs/openapi.json机器可读的 OpenAPI 规范适合导入 Postman、编写 SDK 或接入 MCPhttps://your-domain/_docs/scalarScalar 交互式 UI可直接在页面里填参数发起真实请求https://your-domain/_docs/swagger经典 Swagger UI这三个路径并非文档约定而是 Nitro 的 OpenAPI 模块在 nuxt.config.ts 中显式配置的openAPI.production设为runtime运行时动态生成始终与当前代码一致route指向/_docs/openapi.jsonui.scalar.route与ui.swagger.route分别对应两个 UI 入口元信息标题为 Sink API。此外配置中还有一处容易忽略的细节/_docs/**路由被附加了X-Robots-Tag: noindex, follow响应头见 nuxt.config.ts意味着 API 文档页默认不进入搜索引擎索引但允许爬虫跟进其内部链接。对 Agent 与 LLM 场景尤其关键的是拿到openapi.json后任何支持 OpenAPI 的工具链都可以直接消费它。仓库 README.md 中给出了一个现成的 MCP 集成方案通过mcp-openapi-proxy将 Sink 暴露为 MCP Server核心配置为{ mcpServers: { sink: { command: uvx, args: [mcp-openapi-proxy], env: { OPENAPI_SPEC_URL: https://your-domain/_docs/openapi.json, API_KEY: YOUR_SITE_TOKEN, TOOL_WHITELIST: /api/link } } } }其中API_KEY就是实例环境变量中的NUXT_SITE_TOKENTOOL_WHITELIST可限定只暴露链接管理相关工具。认证机制Bearer Token 与 Cloudflare AccessSite Token 认证所有/api/**请求必须携带站点密码通过标准Authorization头传递Authorization: Bearer YOUR_SITE_TOKENBearer前缀只是这里跟着令牌的语义约定会被服务端剥离。令牌必须与环境变量NUXT_SITE_TOKEN完全一致且至少 8 个字符。从源码可以确认三个关键实现细节见 server/middleware/2.auth.ts中间件只拦截 API 路径event.path.startsWith(/api/)之外的请求页面、静态资源、/_docs/**直接放行认证只约束 API 面。令牌比较是时序安全的verifySiteToken不会直接字符串比较而是对双方令牌分别做 SHA-256 摘要后用 Node 的timingSafeEqual对比见 server/middleware/2.auth.ts避免计时侧信道泄露令牌信息。错误码分层携带了令牌但长度不足 8 时返回401 Token is too short令牌校验失败返回401 Unauthorized。通过验证后中间件将身份写入请求上下文authMethod: site-token、userID: root、userEmail: root请求域名后续/api/verify会回显这些信息。另外Site Token 有默认值兜底nuxt.config.ts 中siteToken取process.env.NUXT_SITE_TOKEN未设置时回退为randomBytes(32)生成的随机串——即不配环境变量也能登录但需要在部署日志或构建产物中找回该值。Cloudflare Access 认证启用 Cloudflare Access 后浏览器可以不用 Site Token直接凭已验证的 Access 登录态访问 API。从 server/middleware/2.auth.ts 可以看到其裁决逻辑当请求带有 Access 身份verifyCloudflareAccess成功时若该身份在策略白名单内isCloudflareAccessRequestAllowed则以 Access 用户/服务身份继续否则返回403 Forbidden。也就是说Access 身份存在但不被允许比无认证更严格会得到 403 而非 401。验证你的认证状态GET /api/verify是最实用的自检端点用于确认当前到底是谁在调用。其实现见 server/api/verify.get.ts会校验上下文中的authMethod合法取值为site-token/access-user/access-service与userID、userEmail缺失则抛 401通过后返回{ name: Sink, url: https://sink.cool, authMethod: site-token, userID: root, userEmail: rootyour-domain, accessEnabled: false }accessEnabled反映当前实例是否配置了 Cloudflare Access由cfAccessTeamDomain与cfAccessAud两个运行时配置决定。接入新实例时建议第一个请求就打/api/verify可以一次性区分令牌错误401与认证方式不符合预期accessEnabled 为 false。CORS允许第三方站点调用 API默认情况下/api/**不携带 CORS 头来自其他站点的浏览器应用无法跨域调用 Sink APIcurl、Postman、服务端到服务端调用不受此影响CORS 只约束浏览器。开启方式是构建期设置环境变量NUXT_API_CORStrue。源码层面的实现是 Nuxt 的 route rules见 nuxt.config.tsrouteRules: { /api/**: { cors: process.env.NUXT_API_CORS true, }, }注意两点该值在构建时被固化进产物改配置后需要重新构建/部署开启 CORS不等于放开认证文档明确强调 Login 仍然必需跨域请求依旧要带Authorization: Bearer ...头且浏览器跨域携带自定义头会触发预检请求令牌不能放进 Cookie。调用链接 API 前存储就绪门禁HTTP 423这是最容易踩坑的一条前置约束。Sink 的权威链接存储在 D1KV 作为写透读缓存部署后需要先到Dashboard → Links打开一次页面来触发存储初始化KV→D1 迁移在此之前调用大多数/api/link/**端点会直接失败错误为storage not readyHTTP 423。迁移的完整流程见 docs/storage/kv-to-d1.md。从 server/middleware/3.link-store-gate.ts 可以精确还原这个门禁的行为只拦截/api/link及/api/link/**路径/api/stats/**等其他 API 不受影响唯一的豁免路径是迁移端点本身正则^\/api\/link\/migration\/(?:status|run)\/?$即migration/status与migration/run在存储未就绪时依然可调这正是用 API 手动完成首次迁移的通道就绪标志是 KV 中的迁移完成标记readCompletedLinkMigrationMarker存在即放行否则抛423 Link migration is required。因此推荐的接入顺序是GET /api/verify确认认证 →GET /api/link/migration/status确认存储 → 若未就绪则POST /api/link/migration/run或到 Dashboard 打开 Links 页 → 之后正常使用链接 API。各端点的语义细节链接管理端点链接组覆盖/api/link/create、edit、upsert、delete、query、search、list、check、tags。其中两个端点的行为值得展开POST /api/link/upsert是幂等的创建或占用检查。请求体字段与 OpenAPI 描述一致见 server/api/link/upsert.post.tsurl必填目标地址、slug自定义短码缺省自动生成、comment、expirationUnix 秒、title/description/image预览定制、apple/google应用商店分流、unsafe标记为不安全链接跳转前展示警告页、geo国家码到 URL 的路由规则、tags最多 10 个规范化标签每个 1–32 字符。其核心语义见 server/api/link/upsert.post.tsslug 空闲时创建返回status: created且 HTTP 201slug 已存在时不覆盖原样返回既有链接并附status: existing并发竞争创建落库时与他人撞车会回读一次权威存储若确实已有该 slug 则同样返回existing仅在无法解释的冲突时抛409 Link already exists。批量脚本可以用这个特性做探测式注册upsert 返回existing即说明该短码已被占用可能是自己的无需额外的查询往返。GET /api/link/search的匹配范围覆盖短码slug、URL、comment 与 tags。从 server/api/link/search.get.ts 的参数校验可见精确边界参数约束q非空、大小写不敏感的子串匹配 slug/URL/comment/tag上限 48 UTF-8 字节url目标 URL 精确匹配先规范化最长 2048 字符tag精确匹配规范化小写标签最长 32 字符statusactive/expired/all默认activelimit1–1000 整数默认 20一个容易误解的点q、tag、status都不是独立搜索条件——没有q或url的请求会直接返回空数组tag与status只对关键词/URL 搜索结果起过滤作用OpenAPI 描述原文如此校验代码if (!query.q !query.url) return []与之对应。其余链接端点的分工源自 docs/api/index.mdcheck由服务端对目标 URL 发起探测不是浏览器探测适合批量巡检死链query/list/tags面向批量读取与标签聚合create/edit/delete对应单条 CRUD。请求体的字段级约束定义在 shared/schemas/link.ts 中CreateLinkSchema、SlugSchema等 zod schemaupsert 的 OpenAPI 请求体即由该 schema 派生。导入/导出与存储迁移/api/link/import、/api/link/export以 JSON 迁移链接数据、导出链接清单字段与限制见 docs/features/import-export.md。构建配置中的importRequestLimit: 100nuxt.config.ts限定了单次导入请求的批量规模。/api/link/migration/status、/api/link/migration/run触发与查询 KV→D1 存储迁移即上文 423 门禁的豁免路径。相关测试覆盖见 tests/api/link-migration.spec.ts 与 tests/api/link.spec.ts可用来验证端点契约。AI 端点/api/link/ai与/api/link/og-ai基于 Cloudflare Workers AI 生成 slug 与 OpenGraph 元数据属于可选能力依赖aiModel、aiPrompt等运行时配置nuxt.config.ts 给出了默认模型与 prompt 模板。详细用法见 docs/features/ai.md。分析端点/api/stats/**与/api/logs/**构成近实时分析的数据面对应 docs/features/analytics.md 中的图表与事件流仪表盘侧通过 10 秒轮询拉取并做客户端回放README 亦明确不使用 SSE/WebSocket。服务端实现分散在 server/api/stats/ 目录下metrics.get.ts、heatmap.get.ts、views.get.ts、counters.get.ts、[action].get.ts测试入口为 tests/api/stats.spec.ts 与 tests/api/logs.spec.ts。工具类端点端点行为与源码依据GET /api/verify回显认证方式与身份见上文认证一节server/api/verify.get.tsGET /api/location返回 Cloudflare 边缘提供的近似经纬度直接读取request.cf中的latitude/longitude见 server/api/location.get.tsCloudflare 未提供坐标时字段可能为空POST /api/upload/image上传图片到 R2 存储multipart/form-data需带file与slug两个字段slug 必须通过短码格式校验仅接受 JPEG/PNG/WebP/GIF上限 5 MB成功后返回/_assets/images/...形式的 URL见 server/api/upload/image.post.ts。未配置 R2 桶时由requireR2Bucket直接报错即该端点是 R2 可选依赖POST /api/backup手动触发一次 JSON 快照备份写入 R2若迁移未完成返回 423未配 R2 桶则要求桶存在见 server/api/backup.post.ts端点分组总表与 docs/api/index.md 保持一致的分组索引完整请求/响应字段以/_docs/scalar交互界面为准分组路由链接管理/api/link/create、edit、upsert、delete、query、search、list、check、tags导入/导出/api/link/import、/api/link/exportdocs/features/import-export.md存储迁移/api/link/migration/status、/api/link/migration/rundocs/storage/kv-to-d1.mdAI/api/link/ai、/api/link/og-aidocs/features/ai.md分析/api/stats/**、/api/logs/**docs/features/analytics.md工具/api/verify、/api/location、/api/upload/image、/api/backup接入检查清单认证Authorization: Bearer NUXT_SITE_TOKEN令牌 ≥8 字符先打GET /api/verify验证CORS仅当跨域浏览器应用需要调用时才在构建期设NUXT_API_CORStrue并重新部署存储门禁部署后先到 Dashboard → Links 打开一次或调migration/status/migration/run规避 423幂等写入批量脚本优先用upsert通过status: created | existing区分新建与占用搜索语义/api/link/search必须带q或url才返回结果tag/status仅作过滤可选依赖图片上传与备份依赖 R2 桶配置AI 端点依赖 Workers AI 配额未配置时对应端点不可用。以上行为均基于当前仓库的中间件、路由实现与构建配置验证适用于仓库当前版本的 Workers 部署形态Pages 部署为已弃用路径。【免费下载链接】Sink⚡ A Simple / Speedy / Secure Link Shortener with Analytics, 100% run on Cloudflare.项目地址: https://gitcode.com/GitHub_Trending/si/Sink创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考