纸鱼博客提供两组 HTTP 接口:
开放 API v1(
/api/v1/...):只读 JSON 接口,使用X-API-Key请求头鉴权,适合静态站、外部前端、聚合工具。App 管理 API(
/api/app/...):给纸鱼手机管理 App 等一方客户端使用,登录后使用Bearer设备令牌,可读取草稿与待审内容并执行受控写操作。
另有供后台编辑器使用的媒体与预览接口(/api/upload、/api/uploads、/api/md-preview、/api/import-markdown),它们需要登录会话和 posts.manage 权限。
API 的基础地址为:
https://你的域名/api/v1
https://你的域名/api/app上面的地址形式适用于启用伪静态的站点。若在安装向导或 runtime/config.php 中关闭 pretty_urls,API 地址使用查询形式,例如 https://你的域名/index.php?p=api/v1/posts;其他查询参数继续用 & 追加。伪静态部署规则参见安装说明。
开启 API
登录后台,进入“站点设置 → 开放 API”:
开启“启用开放 API”。
生成或复制 API Key。
按需设置每分钟请求上限、单页最大条数和 CORS 来源。
API Key 只应保存在服务端或受信任的应用中,不要写入公开的前端代码。Key 泄露后请立即重新生成,旧 Key 会失效。
请求鉴权
所有 /api/v1 接口都需要在请求头中携带:
X-API-Key: 你的 API Key已通过 Authorization: Bearer <设备令牌> 鉴权的请求会直接放行,不再要求 API Key。这条规则只对本次请求有效,不会建立浏览器会话。
/api/v1/categories 与 /api/v1/tags 同时接受设备令牌,供 App 编辑器加载分类和标签候选;其余 v1 接口仍使用 API Key。
示例:
curl -H "X-API-Key: 你的 API Key" \
https://example.com/api/v1/posts文章列表
GET /api/v1/posts查询参数:
参数 | 必填 | 说明 |
|---|---|---|
| 否 | 页码,从 |
| 否 | 每页数量,默认 |
| 否 | 分类 slug,同时包含该分类的子分类 |
| 否 | 标签 slug |
| 否 | 在标题和正文中搜索关键词 |
示例:
curl -G -H "X-API-Key: 你的 API Key" \
--data-urlencode "page=1" \
--data-urlencode "perPage=10" \
--data-urlencode "category=php" \
https://example.com/api/v1/posts只返回已发布且已到发布时间的文章。返回示例:
{
"posts": [
{
"id": "1",
"title": "文章标题",
"slug": "article-slug",
"excerpt": "文章摘要",
"coverUrl": null,
"publishedAt": "2026-09-13T02:00:00Z",
"viewCount": 12,
"likeCount": 3,
"favoriteCount": 1,
"isPinned": false,
"categoryPinned": false,
"hasPassword": false,
"commentsEnabled": true,
"externalUrl": null,
"category": {"name": "技术", "slug": "tech"},
"tags": [{"name": "PHP", "slug": "php"}],
"author": "admin"
}
],
"total": 1,
"page": 1,
"perPage": 10,
"totalPages": 1
}列表接口不返回正文。密码文章只返回 hasPassword: true,摘要统一替换为固定提示,不泄露原文。
文章详情
GET /api/v1/posts/{slug}示例:
curl -H "X-API-Key: 你的 API Key" \
https://example.com/api/v1/posts/article-slug返回文章列表中的全部字段,并额外包含:
字段 | 说明 |
|---|---|
| 文章正文 |
| 正文格式, |
| 最后更新时间,UTC ISO-8601 格式 |
| 自定义 SEO 标题,空字符串表示沿用自动标题 |
| 自定义描述,空字符串表示沿用自动描述 |
| 自定义字段数组,每项为 |
草稿、回收站文章、未到发布时间的定时文章和不存在的 slug 都返回 404。设置了密码的文章返回 403,响应体为 {"error":"文章需要密码","hasPassword":true}。
分类、标签和站点信息
GET /api/v1/categories
GET /api/v1/tags
GET /api/v1/site分类返回 id、name、slug、description、coverUrl、seoTitle、metaDescription、parentId 和 postCount。标签返回 id、name、slug、description、seoTitle、metaDescription 和 postCount。
站点信息返回一个 site 对象,包含 name、subtitle、description、url 和 version。
评论列表
GET /api/v1/comments?postId=1&page=1&perPage=50postId 必填;page 默认 1,perPage 默认 50,最大值为 100。接口只返回已审核通过的评论。目标文章不可公开读取时返回对应的 404 或 403。
返回字段包括 id、postId、parentId、authorName、content、createdAt 和 isPinned。createdAt 使用 UTC ISO-8601 格式,parentId 可用于还原楼中楼结构。评论返回不含点赞数字段。
页面、友链和导航
GET /api/v1/pages
GET /api/v1/links
GET /api/v1/menus这些接口分别返回已发布的独立页面、可见友链和可见导航项,不分页。
微语列表
GET /api/v1/micro-statuses返回公开微语列表,支持 page、perPage(默认 10,上限 50)。草稿、私密、软删除和未来发布时间的内容不会返回。响应字段为 items、total、page、perPage、totalPages,每项包含 id、content、contentFormat、publishedAt、updatedAt、isPinned、isPrivate、author(对象:id、name、avatarUrl)和 media。
CORS
后台“开放 API”中的“CORS 来源”支持填写一个或多个来源,多个来源用逗号分隔,例如:
https://app.example.com, https://admin.example.com留空表示不返回 CORS 响应头。配置 * 可以允许任意来源,但不建议与公开部署的 API Key 一起使用。
限流与错误响应
默认每个 API Key 和客户端 IP 每分钟最多请求 120 次,可在后台修改;设为 0 表示不限制。超过限制返回 429。
错误响应为 JSON:
{"error":"无效的 API Key"}常见状态码:
状态码 | 说明 |
|---|---|
| 请求参数缺失或格式错误 |
| API 未启用、API Key 无效或设备令牌失效 |
| 文章设置了密码,或当前身份无权访问 |
| 文章、分类或资源不存在 |
| 请求超过限流值 |
后台编辑器接口
以下接口使用浏览器登录会话(admin_token Cookie),需要 posts.manage 权限。POST 请求必须携带 _csrf 表单字段或 X-CSRF-Token 请求头;携带已校验设备令牌的请求同样可调用,但只限受控后台写操作白名单,完整规则见App 接口与设备令牌。
上传文件
POST /api/upload
Content-Type: multipart/form-data字段名 file,也可以重复提交 file[] 上传多个文件。返回 ok、url、mime、originalName、size、width、height,以及兼容旧编辑器的 data.succMap / data.errMap。
分片上传
POST /api/upload/chunk
Content-Type: multipart/form-data用于超出 post_max_size 的大文件。字段为 file(当前分片)、upload_id(24–64 位十六进制上传会话标识)、chunk_index(从 0 开始)、chunk_total(最多 256)、filename。单片上限 1MB。
未集齐时返回 {"ok":true,"complete":false,"uploaded":字节数};集齐后合并、走正常上传管线(图片压缩、水印、云存储)并返回 {"ok":true,"complete":true,"url":...}。临时分片存放在 storage/chunks/,超过 24 小时的会话会被清理,因此该目录需要可写。
媒体库
GET /api/uploads?page=1&q=关键词&type=image每页 24 条。type 可选 image、doc、archive、audio、video。非管理员只能看到自己上传的文件。
Markdown 预览
POST /api/md-preview
Content-Type: application/json
{"content": "**预览**", "content_format": "markdown"}返回 {"html":"<p><strong>预览</strong></p>"}。content_format 支持 markdown 和 html,后者会经过 HTML 白名单净化。
批量导入 Markdown
POST /api/import-markdown
Content-Type: multipart/form-data字段 files[] 最多 50 个 .md 文件,单文件上限 1MB;可选 status:draft(默认)或 publish。frontmatter 只解析 title、date 和 tags。缺失标题时使用文件名;slug 冲突时自动追加 -2、-3。导入同样经过 before_post_save 决策过滤器。
内容控制与栏目资料字段
文章列表和详情包含
commentsEnabled:全站评论启用且该文章允许新评论时为true。关闭新评论不影响读取原有已审核评论。文章详情额外返回
seoTitle、metaDescription;密码文章仍遵守读取限制,不通过这些字段绕过密码校验。分类项包含
coverUrl、seoTitle、metaDescription。标签项包含
description、seoTitle、metaDescription。页面项包含
seoTitle、metaDescription。友链项包含
iconUrl。SEO 字段为空表示沿用自动标题/描述;接口返回原始配置,不拼接站点名称。图片地址可能是站内路径或 HTTP(S) URL,未设置时为
null。