LibreKB 2.3.3 API 使用详解

LibreKB 2.3.3 只读 JSON API 六端点 curl 全实测:X-API-Key/query 双认证、401/403/404/405/400/503 全错误码实录、可见性过滤、分页约定、维护模式联动与 CORS 预检。

LibreKBLibreKB文档管理WikiDocs2026/11/02

LibreKB 2.3.3 API 使用详解

目标:LibreKB 2.3.3 只读 JSON API 的全部 6 个端点、认证方式、可见性规则与错误码逐条 curl 实测——从默认 503 到开启后 200、401/403/404/405/400/503 全分支回显照抄。实测环境:http://192.168.1.200:8139(LibreKB 2.3.3 + PHP 8.4.27 + MySQL 8.0.46,2026-11-01)。

一、环境信息

  • 软件:LibreKB 2.3.3(API 自 v2.2.0 引入,README 实查)
  • API 前缀:/api/v1,只读 JSON,Content-Type: application/json; charset=utf-8
  • 认证:X-API-Key 请求头或 api_key 查询参数(密钥在后台 Settings→API 配置)
  • 测试数据:4 个分类(含 1 个禁用、1 个嵌套子分类)、5 篇文章(含 1 篇禁用、1 篇在禁用分类内)、1 个附件
  • 演示密钥:librekb-demo-key-2026;管理员账号 admin@kb.example.com / q1w2e3r4
  • 客户端工具:curl 8.18.0

二、前置条件

API 默认关闭,直接调用返回 503(实录):

$ curl -s -w "\nHTTP %{http_code}\n" http://192.168.1.200:8139/api/v1/categories
{"error":"The API is disabled."}
HTTP 503

开启方式(后台 Settings→API 分区,脚本化等价命令,csrf_token 从表单页提取):

$ curl -s -b cookies.txt -c cookies.txt -w "POST /admin/settings/api -> HTTP %{http_code}\n" \
    http://192.168.1.200:8139/admin/settings/api \
    --data-urlencode "csrf_token=..." \
    --data-urlencode "api_enabled=enabled" \
    --data-urlencode "api_key=librekb-demo-key-2026" \
    --data-urlencode "api_cors_origin=*"
POST /admin/settings/api -> HTTP 302

三个设置项的取值规则与校验实测见《LibreKB 2.3.3 配置参数详解》(https://www.quzuo.net/document/0NMKA1ZoNL9x)API 分区一节。

三、API 总览

端点方法说明
/api/v1/articles/searchGET全文检索(标题+内容),分页,返回摘要+附件元数据
/api/v1/articles/{id}GET按数字 ID 取文章(含清洗后 HTML 正文)
/api/v1/articles/slug/{slug}GET按 slug 取文章(含正文)
/api/v1/categoriesGET启用分类树(递归 children,含 article_count)
/api/v1/categories/{id}GET按 ID 取单分类(含子树与该分类文章列表)
/api/v1/categories/slug/{slug}GET按 slug 取单分类(同上)
以上全部OPTIONSCORS 预检,204

约定:仅接受 GET(其余方法 405);无内建限流;可见性与前台严格一致——禁用文章、禁用分类(含祖先被禁用)下的启用文章一律 404/省略;维护模式期间全部 503。响应头固定携带 X-Content-Type-Options: nosniff 与 Cache-Control: no-store。

四、认证与首次调用

设置密钥后,无 key 与错 key 都是 401(实录):

$ curl -s -w "\nHTTP %{http_code}\n" http://192.168.1.200:8139/api/v1/categories
{"error":"A valid API key is required."}
HTTP 401

$ curl -s -w "\nHTTP %{http_code}\n" -H "X-API-Key: nope-nope-nope-0000" \
    http://192.168.1.200:8139/api/v1/categories
{"error":"A valid API key is required."}
HTTP 401

带正确密钥的首次调用:

$ curl -s -w "\nHTTP %{http_code}\n" -H "X-API-Key: librekb-demo-key-2026" \
    http://192.168.1.200:8139/api/v1/categories
{"categories":[{"id":1,"name":"Getting Started","slug":"getting-started","description":"First steps with the knowledge base.","icon":"book","parent_id":null,"article_count":2,"children":[{"id":4,"name":"First Steps","slug":"first-steps","description":"Nested under Getting Started.","icon":"","parent_id":1,"article_count":0,"children":[]}]},{"id":2,"name":"Troubleshooting","slug":"troubleshooting","description":"Common problems and fixes.","icon":"wrench","parent_id":null,"article_count":1,"children":[]}]}
HTTP 200

注意返回中只有 2 个顶层分类:禁用的 Draft Area(id=3)被整体省略,子分类 First Steps 挂在父节点 children 里。

api_key 也支持查询参数形式(浏览器/不便加头的客户端):

$ curl -s "http://192.168.1.200:8139/api/v1/categories?api_key=librekb-demo-key-2026" | head -c 120
{"categories":[{"id":1,"name":"Getting Started","slug":"getting-started","description":"First steps with the knowledge base.","icon

⚠️ 注意:query 形式会把密钥留在访问日志里,生产优先用 X-API-Key 头。密钥超过 128 字符按未提供处理。

特殊组合:密钥留空且知识库 private 时返回 403(而非 401):

$ curl -s -w "\nHTTP %{http_code}\n" http://192.168.1.200:8139/api/v1/categories
{"error":"An API key is required when the knowledge base is private."}
HTTP 403

五、各 API 域详解

5.1 文章搜索 GET /api/v1/articles/search

参数:q(必填,≤200 字符)、page(默认 1)、per_page(默认 20,上限 50)。

$ curl -s -H "X-API-Key: librekb-demo-key-2026" \
    "http://192.168.1.200:8139/api/v1/articles/search?q=password"
{"query":"password","page":1,"per_page":20,"total":2,"articles":[{"id":3,"title":"Fixing Login Issues","slug":"fixing-login-issues","category":{"id":2,"name":"Troubleshooting","slug":"troubleshooting"},"attachments":[]},{"id":1,"title":"Reset Your Password","slug":"reset-your-password","category":{"id":1,"name":"Getting Started","slug":"getting-started"},"attachments":[{"id":1,"name":"att-demo.txt","size":64,"mime":"text/plain","url":"http://192.168.1.200:8139/attachment/1"}]}]}
HTTP 200

结果不含正文(摘要形态),但带附件元数据;命中禁用文章 Unpublished Draft 与禁用分类下的文章为 0 条——可见性过滤在 SQL 层完成。

错误分支实测:

$ curl -s -H "X-API-Key: librekb-demo-key-2026" "http://192.168.1.200:8139/api/v1/articles/search?q=password&per_page=100"
{"error":"Invalid per_page."}
HTTP 400

$ curl -s -H "X-API-Key: librekb-demo-key-2026" "http://192.168.1.200:8139/api/v1/articles/search?q="
{"error":"A search query is required."}
HTTP 400

5.2 文章详情 GET /api/v1/articles/{id} 与 /articles/slug/{slug}

$ curl -s -H "X-API-Key: librekb-demo-key-2026" http://192.168.1.200:8139/api/v1/articles/1
{"article":{"id":1,"title":"Reset Your Password","slug":"reset-your-password","content":"<p>Use the <strong>Forgot password</strong> link on the login page. A reset email is sent to your address.</p>","category":{"id":1,"name":"Getting Started","slug":"getting-started"},"attachments":[{"id":1,"name":"att-demo.txt","size":64,"mime":"text/plain","url":"http://192.168.1.200:8139/attachment/1"}],"created":"2026-11-01 15:54:50","updated":"2026-11-01 15:54:50"}}
HTTP 200

$ curl -s -H "X-API-Key: librekb-demo-key-2026" \
    http://192.168.1.200:8139/api/v1/articles/slug/how-to-search-the-knowledge-base
{"article":{"id":2,"title":"How to Search the Knowledge Base","slug":"how-to-search-the-knowledge-base","content":"<p>Type a query in the search box. Results match titles and content.</p>","category":{"id":1,"name":"Getting Started","slug":"getting-started"},"attachments":[],"created":"2026-11-01 15:54:50","updated":"2026-11-01 15:54:50"}}
HTTP 200

content 是前台同款清洗后 HTML;attachments[].url 为 systemURL 拼出的绝对地址(改 config.php 的 systemURL 会同步变化)。隐藏内容实测(禁用文章 id=4、禁用分类下的启用文章 id=5):

$ curl -s -H "X-API-Key: librekb-demo-key-2026" http://192.168.1.200:8139/api/v1/articles/4
{"error":"Article not found."}
HTTP 404
$ curl -s -H "X-API-Key: librekb-demo-key-2026" http://192.168.1.200:8139/api/v1/articles/5
{"error":"Article not found."}
HTTP 404

5.3 分类 GET /api/v1/categories/{id} 与 /categories/slug/{slug}

$ curl -s -H "X-API-Key: librekb-demo-key-2026" http://192.168.1.200:8139/api/v1/categories/1
{"category":{"id":1,"name":"Getting Started","slug":"getting-started","description":"First steps with the knowledge base.","icon":"book","parent_id":null,"article_count":2,"children":[{"id":4,"name":"First Steps","slug":"first-steps","description":"Nested under Getting Started.","icon":"","parent_id":1,"article_count":0,"children":[]}],"articles":[{"id":1,"title":"Reset Your Password","slug":"reset-your-password","attachments":[{"id":1,"name":"att-demo.txt","size":64,"mime":"text/plain","url":"http://192.168.1.200:8139/attachment/1"}]},{"id":2,"title":"How to Search the Knowledge Base","slug":"how-to-search-the-knowledge-base","attachments":[]}]}}
HTTP 200

$ curl -s -H "X-API-Key: librekb-demo-key-2026" \
    http://192.168.1.200:8139/api/v1/categories/slug/troubleshooting
{"category":{"id":2,"name":"Troubleshooting","slug":"troubleshooting","description":"Common problems and fixes.","icon":"wrench","parent_id":null,"article_count":1,"children":[],"articles":[{"id":3,"title":"Fixing Login Issues","slug":"fixing-login-issues","attachments":[]}]}}
HTTP 200

单分类响应 = 分类节点 + 递归 children 子树 + 直属 articles 列表;article_count 为含子分类的递归计数。禁用分类(id=3)同样 404:

$ curl -s -H "X-API-Key: librekb-demo-key-2026" http://192.168.1.200:8139/api/v1/categories/3
{"error":"Category not found."}
HTTP 404

5.4 方法限制与 CORS

非 GET 方法 405 并带 Allow 头:

$ curl -s -X POST -D - -o /dev/null -H "X-API-Key: librekb-demo-key-2026" \
    http://192.168.1.200:8139/api/v1/categories | grep -iE "^(HTTP|allow)"
HTTP/1.1 405 Method Not Allowed
Allow: GET, OPTIONS
$ curl -s -X POST -H "X-API-Key: librekb-demo-key-2026" http://192.168.1.200:8139/api/v1/categories
{"error":"Method not allowed."}

浏览器跨域预检 204,CORS 头组实测(api_cors_origin=* 时):

$ curl -s -X OPTIONS -D - -o /dev/null http://192.168.1.200:8139/api/v1/categories -H "Origin: http://app.example.com" | head -15
HTTP/1.1 204 No Content
Server: Apache/2.4.69 (Debian)
X-Powered-By: PHP/8.4.27
X-Frame-Options: DENY
Access-Control-Allow-Origin: *
Vary: Origin
Access-Control-Allow-Methods: GET, OPTIONS
Access-Control-Allow-Headers: X-API-Key, Content-Type
Access-Control-Max-Age: 600
Allow: GET, OPTIONS

未知 API 路径 404:

$ curl -s -H "X-API-Key: librekb-demo-key-2026" http://192.168.1.200:8139/api/v1/unknown
{"error":"Not found."}
HTTP 404

5.5 维护模式联动

后台开启 Maintenance 后 API 整体 503(优先级高于 key 校验):

$ curl -s -w "\nGET /api/v1/categories -> HTTP %{http_code}\n" \
    -H "X-API-Key: librekb-demo-key-2026" http://192.168.1.200:8139/api/v1/categories
{"error":"The knowledge base is undergoing maintenance."}
GET /api/v1/categories -> HTTP 503

六、分页/过滤/排序通用约定

  • 分页仅搜索端点支持:page 从 1 起(上限 1000,超限 400 Invalid page.),per_page 默认 20、上限 50(超限 400 Invalid per_page.),非数字同样 400;
  • 响应携带 query/page/per_page/total 元数据,客户端可用 ceil(total/per_page) 自行算页数;
  • 无过滤/排序参数:搜索按标题+内容匹配,列表按后台 order 字段与 ID 排序,API 不接受覆盖;
  • 分类树无分页(整树返回),文章列表字段(articles[])不分页;
  • 所有 ID 参数必须是 1–2147483647 的纯数字,slug 参数拒绝控制字符与超长值(400 Invalid id./Invalid slug.)。

七、常见问题

7.1 错误码速查

状态码场景(均实测)响应体
200正常读取数据 JSON
400per_page/page 非法、空查询、非法 id/slug{"error":"Invalid per_page."} 等
401已设 key 而缺失/错误{"error":"A valid API key is required."}
403key 留空 + 知识库 private{"error":"An API key is required when the knowledge base is private."}
404未知路径、隐藏/不存在的文章与分类{"error":"Not found."} / Article not found. / Category not found.
405POST/PUT/DELETE 等{"error":"Method not allowed."} + Allow: GET, OPTIONS
503API 开关关闭或维护模式{"error":"The API is disabled."} / The knowledge base is undergoing maintenance.

7.2 内容明明存在却 404

检查三处可见性:文章 status 是否 disabled、所属分类是否 disabled、分类祖先链是否 disabled——任一命中即与前台一致地隐藏,这是设计行为而非故障。

7.3 附件 url 指向错误主机

attachments[].url 由 config.php 的 systemURL 拼接(实测值 http://192.168.1.200:8139/attachment/1)。反向代理场景把 systemURL 配成对外 HTTPS 地址即可。

7.4 想要写入 API(建文章/分类)

v2.3.3 不提供:路由层只注册 GET/OPTIONS,任何写操作 405。自动化写入只能走数据库或后台表单(带 CSRF 的脚本化 POST 实测见部署指南 4.5 节)。

7.5 前端 fetch 被 CORS 拦

后台 API 分区把 api_cors_origin 设为具体前端 origin(或 *),浏览器预检即可通过(204 + Access-Control-Allow-Headers: X-API-Key, Content-Type 实测见 5.4)。

八、参考链接

LibreKB 2.3.3 API 使用详解 - Quzuo