API 文档

更新于 2026-11-08 15:31:53 23 次浏览

本文档面向对接小程序、移动 App 等第三方客户端的开发者,描述 BlogKit 开放 API 的使用方式。适用 API 版本:v1。

1. 概述

BlogKit 的开放 API 由「开放API」插件提供,统一入口为站点根目录下的 api.php。主系统本身不实现任何 API 逻辑;未安装或未启用该插件时,api.php 返回:

{"code": 404, "message": "API 功能未启用:请安装并启用 openapi(开放API套件)插件"}

能力范围:文章、评论、分类、标签、页面、用户、搜索、通知的查询与写入,登录注册等认证接口,图片/文件/头像上传,系统信息查询。

基础地址:{站点域名}/api.php,路径中带版本段,如 /api.php/v1/articles。

版本机制:路径前缀 /api.php/v1/...(推荐);或请求头 Accept-Version: v1;两者均未提供时使用后台配置的默认版本(默认 v1)。每个响应附带 X-API-Version 响应头;请求未启用的版本时返回 404:{"code": 404, "message": "API版本无效", "data": {"requested_version": "v2", "supported_versions": ["v1"]}}。

2. 快速开始

  1. 后台进入「插件管理」,安装并启用「开放API」插件(openapi)。
  2. 后台进入「插件管理 → 插件详情 → 配置」:确认「启用API功能」已开启;在密钥管理中创建 API 密钥(填写名称、平台,可选配置 IP 白名单、域名白名单、限流与过期时间)。密钥明文仅在创建时展示一次,请立即保存。
  3. 验证安装,请求测试接口:
curl http://example.com/api.php/v1/test
{"code": 200, "message": "测试成功", "data": {"message": "API路由测试成功", "request_path": {}, "request_method": "GET"}}
  1. 获取文章列表(公开接口,无需认证):curl "http://example.com/api.php/v1/articles?page=1&page_size=5"。

3. 认证方式

3.1 认证模式

后台「API 设置」中的「认证方式」(api_auth_type)决定鉴权模式:

  • session(默认):基于登录会话。调用 POST /auth/login 成功后服务端建立会话,客户端后续携带会话 Cookie 访问需登录接口;登录响应中的 token 字段为服务端生成的令牌(有效期由「Token过期时间」配置控制,默认 3600 秒),可通过 /auth/refresh-token 刷新。
  • api_key:基于 API 密钥,密钥在每次请求中传递(见 3.2)。

两种模式共存:带会话 Cookie 的调用走会话认证,带密钥的调用走密钥认证。通过 API Key 认证的请求在接口层视为管理员身份(可调用分类、标签、页面的管理接口)。

3.2 API 密钥的传递

方式示例说明
请求头API-Key: <你的密钥>推荐
查询参数?api_key=<你的密钥>通用,适合无法自定义请求头的场景

说明:入口分发层额外识别 X-API-Key 请求头,但部分接口的控制器在会话缺失时仅从 API-Key 请求头或 api_key 参数读取密钥,因此第三方客户端请统一使用上表两种方式。

3.3 密钥校验规则

每次使用密钥的请求,服务端依次校验:密钥有效性(bcrypt 加密存储、指纹定位后校验)→ 状态(已撤销 inactive 或已过期 expired 拒绝访问)→ 过期时间 → IP 白名单(逗号分隔,比对客户端 IP)→ 域名白名单(逗号分隔,比对请求 Referer)→ 接口权限(若密钥配置了 permissions,即允许访问的接口路径 JSON 数组,请求路径必须命中列表)→ 密钥级限流(按密钥设置的次数与时间窗口计数)。

3.4 认证错误示例

未提供或无效密钥(访问需认证接口时):{"code": 401, "message": "认证失败,请检查认证信息"}。

密钥存在但校验不通过时返回 403,message 取以下值之一:无效的API Key、API Key已被撤销、API Key已过期、IP地址不在白名单中、域名不在白名单中、API Key没有访问该资源的权限、API Key请求频率超过限制。例如:{"code": 403, "message": "IP地址不在白名单中"}。

3.5 会话模式下的 CSRF 校验

session 模式下,写请求(POST/PUT/DELETE)默认须通过 CSRF 校验:在请求体中携带 csrf_token 字段,或请求头 X-CSRF-Token(也接受 X-XSRF-Token、X-CSRFToken)。携带 API 密钥的请求豁免 CSRF 校验。后台关闭「CSRF 防护」后全部放行。

3.6 接口鉴权级别

  • 公开接口:各列表/详情查询、搜索、系统信息、登录注册等;
  • 需登录:文章/评论的写操作、点赞/收藏/关注、我的收藏/点赞/历史、令牌刷新等(session 模式要求会话用户;api_key 模式要求有效密钥);
  • 需登录会话:上传接口、通知接口基于登录会话鉴权,不支持纯密钥调用;
  • 需管理员:分类/标签/页面的写操作、删除用户(session 模式要求管理员会话;api_key 模式视为管理员)。

4. 通用约定

4.1 响应格式

所有接口返回统一包裹结构:code 为业务状态码(与 HTTP 语义一致),message 为提示文本,data 为数据负载(失败时通常为 null)。框架层错误(限流、接口不存在等)的响应额外携带 timestamp 字段(Unix 时间戳)。

{"code": 200, "message": "获取成功", "data": {}}

4.2 分页

列表接口通用请求参数:

参数类型必填说明
pageint否页码,默认 1
page_sizeint否每页数量,默认取后台配置(默认 20),上限取后台配置(默认 100),小于 1 时按 1 处理

分页响应的 data 结构(下文「分页响应」均指此结构):

{
    "items": [],
    "pagination": {"total": 42, "page": 1, "page_size": 20, "total_pages": 3, "has_next": true, "has_prev": false}
}

4.3 时间格式

created_at、updated_at 等时间字段为 Unix 时间戳(秒);文章详情额外返回 created_at_formatted(格式 Y-m-d H:i:s);/system/info 的 server_time 为 Y-m-d H:i:s 格式文本。

4.4 错误码表

code说明常见场景
200成功—
400请求参数错误缺少必填参数、字段校验失败、ID 无效
401未认证未登录、密钥缺失或无效、用户名或密码错误
403禁止访问权限不足、API 功能被禁用、依赖插件未启用、CSRF 校验失败、白名单或权限拦截
404资源不存在数据不存在、接口路径或 API 版本无效
429请求过于频繁触发全局限流
500服务器内部错误服务端异常,生产环境返回通用提示「服务器繁忙,请稍后重试」

字段校验失败(400)时响应附带 errors 对象:{"code": 400, "message": "参数验证失败", "errors": {"title": "title不能为空"}}。API 功能总开关关闭时,所有请求返回 {"code": 403, "message": "API功能已禁用"}。

4.5 插件依赖

通知接口(/notifications*)与文章点赞/收藏写入接口依赖「消息通知」插件;文章与评论的点赞/取消点赞、收藏/取消收藏、关注关系、我的收藏/点赞/阅读历史接口依赖「互动增强」插件。对应插件未启用时返回 403,message 形如「互动功能未启用:请安装并启用 interaction(互动增强)插件」。

5. 接口列表

以下路径省略基础地址与版本前缀,实际请求如 {站点域名}/api.php/v1/articles。请求体支持表单或 JSON(application/json);PUT/DELETE 仅支持 JSON 请求体。

5.1 系统接口

GET /system/config — 获取公开站点配置

无参数。data 为公开配置项:site_name、site_url、site_description、site_keywords、pagination_count、comment_enabled、like_enabled、favorite_enabled、follow_enabled、read_history_enabled、message_enabled、message_duration、register_enabled、login_enabled、api_enabled、rewrite_enabled。

GET /system/info — 获取系统信息

{"code": 200, "message": "获取成功", "data": {"version": "1.0.0", "name": "BlogKit", "description": "一个轻量博客站点", "php_version": "8.2.0", "server_time": "2026-10-09 12:00:00"}}

GET /system/stats — 获取内容统计

{"code": 200, "message": "获取成功", "data": {"articles": 12, "users": 3, "comments": 45, "categories": 5, "tags": 18}}

GET /test — 路由测试

无参数,响应示例见「快速开始」。data.request_path 为本次请求的查询参数。

5.2 认证接口

POST /auth/login — 用户登录

参数类型必填说明
usernamestring是用户名
passwordstring是密码
curl -X POST "http://example.com/api.php/v1/auth/login" \
     -H "Content-Type: application/json" \
     -d '{"username": "demo", "password": "123456"}'
{"code": 200, "message": "登录成功", "data": {"user_id": 1, "username": "demo", "nickname": "演示用户", "email": "demo@example.com", "token": "a1b2c3d4e5f6g7h8", "token_expire": 3600}}

可能错误:401 用户名或密码错误;403 用户已被禁用。session 模式下登录成功即建立会话,需登录接口须携带会话 Cookie。

POST /auth/register — 用户注册

参数类型必填说明
usernamestring是用户名,3-50 个字符
passwordstring是密码,6-50 个字符
emailstring是合法邮箱
nicknamestring否昵称,缺省取用户名

成功:{"code": 200, "message": "注册成功", "data": {"user_id": 5}}。可能错误:400 用户名已存在、邮箱已被注册、参数校验失败。

POST /auth/logout — 退出登录(需登录)

无参数。成功:{"code": 200, "message": "退出成功", "data": null}。

POST /auth/forgot-password — 忘记密码

参数:email(string,必填,注册邮箱)。成功:data 为 null,message 为「重置邮件已发送」,服务端生成有效期 24 小时的重置令牌。可能错误:400 邮箱未注册。

POST /auth/reset-password — 重置密码

参数:email(string,必填,注册邮箱)、token(string,必填,重置令牌)、password(string,必填,新密码,6-50 个字符)。成功:{"code": 200, "message": "密码重置成功", "data": null}。可能错误:400 邮箱未注册、重置令牌无效、重置令牌已过期。

POST /auth/refresh-token — 刷新令牌(需登录)

{"code": 200, "message": "Token刷新成功", "data": {"user_id": 1, "username": "demo", "token": "a1b2c3d4e5f6g7h8", "token_expire": 3600}}

5.3 文章接口

GET /articles — 文章列表

参数类型必填说明
pageint否页码
page_sizeint否每页数量
category_idint否按分类筛选
tag_idint否按标签筛选
statusint否状态:1-已发布(默认)、0-草稿
searchstring否关键词过滤

data.items 元素为文章表全量字段及关联字段,节选如下:

{
    "id": 1,
    "title": "第一篇文章",
    "content": "正文内容……",
    "excerpt": "摘要……",
    "cover_image": "/uploads/images/2026/10/09/image_xxx.png",
    "category_id": 1,
    "user_id": 1,
    "status": 1,
    "view_count": 128,
    "like_count": 6,
    "comment_count": 3,
    "top_type": 0,
    "slug": "hello-blogkit",
    "created_at": 1760000000,
    "updated_at": 1760000000,
    "category_name": "默认分类",
    "category_slug": "default",
    "author": "演示用户",
    "username": "demo",
    "favorite_count": 2
}

GET /articles/{id} — 文章详情

路径参数 id。字段同列表元素,额外返回 created_at_formatted 与 views;访问详情会使文章阅读量加一。可能错误:400 文章ID无效;404 文章不存在。

GET /articles/top — 置顶文章列表

参数:top_types(string,可选,置顶类型逗号分隔,默认 1,2,3,即 1-全局置顶、2-首页置顶、3-分类置顶)、category_id(int,可选,分类置顶时使用)、limit(int,可选,数量上限,默认 10)。data 为文章数组,不分页。

GET /articles/search — 搜索文章

参数:keyword(string,必填,搜索关键词)、page/page_size(int,可选,分页参数)。分页响应。可能错误:400 搜索关键词不能为空。

POST /articles — 创建文章(需登录)

参数类型必填说明
titlestring是标题,最长 60 字符
contentstring是正文内容
category_idint是分类 ID
tagsstring否标签,逗号分隔
statusint否0-草稿(默认)、1-发布
excerptstring否摘要,最长 200 字符

成功:{"code": 200, "message": "文章创建成功", "data": {"article_id": 9}}。可能错误:400 参数校验失败或长度超限;401 未登录;403 新注册账号处于发帖限制期。

PUT /articles/{id} — 更新文章(需登录,仅作者)

路径参数 id。请求体字段均可选:title、content、category_id、tags、status、excerpt,仅更新传入的字段。成功:{"code": 200, "message": "文章更新成功", "data": null}。可能错误:400 文章ID无效;401 未登录;403 无权修改此文章;404 文章不存在。

DELETE /articles/{id} — 删除文章(需登录,仅作者)

成功:{"code": 200, "message": "文章删除成功", "data": null}。可能错误:400 文章ID无效;401 未登录;403 无权删除此文章;404 文章不存在。

POST /articles/{id}/like 与 POST /articles/{id}/unlike — 点赞 / 取消点赞文章(需登录)

成功分别返回 {"code": 200, "message": "点赞成功", "data": {"like_count": 7}} 与 {"code": 200, "message": "取消点赞成功", "data": {"like_count": 6}}。依赖「互动增强」「消息通知」插件。

POST /articles/{id}/favorite 与 POST /articles/{id}/unfavorite — 收藏 / 取消收藏文章(需登录)

成功分别返回 {"code": 200, "message": "收藏成功", "data": {"favorite_count": 3}} 与 {"code": 200, "message": "取消收藏成功", "data": {"favorite_count": 2}}。依赖「互动增强」「消息通知」插件。

POST /articles/{id}/top — 设置文章置顶(需登录,作者或管理员)

参数:top_type(int,必填,0-取消置顶、1-全局置顶、2-首页置顶、3-分类置顶)。成功:{"code": 200, "message": "置顶设置成功", "data": {"top_type": 1}}。可能错误:400 文章ID无效或置顶类型无效;403 无权设置此文章置顶;404 文章不存在。

5.4 评论接口

GET /articles/{article_id}/comments — 文章评论列表

通用分页参数(page、page_size)。评论按 parent_id 组织为两级树结构,每条评论的 replies 数组存放子评论。元素字段节选:

{
    "id": 10,
    "article_id": 1,
    "parent_id": 0,
    "user_id": 2,
    "content": "写得不错",
    "status": 1,
    "is_top": 0,
    "created_at": 1760001000,
    "username": "zhangsan",
    "nickname": "张三",
    "avatar": "/uploads/avatars/avatar_2_xxx.png",
    "user_liked": 0,
    "is_author": 0,
    "replies": []
}

可能错误:400 文章ID无效;404 文章不存在。

POST /articles/{article_id}/comments — 发表评论(需登录)

参数:article_id(int,必填,文章 ID,服务端从请求体读取)、content(string,必填,评论内容)。成功:{"code": 200, "message": "评论发表成功", "data": {"comment_id": 11}}。注意:article_id 须通过请求体传入,路径中的 article_id 不参与解析,请保证两者一致。可能错误:400 文章ID无效或评论内容为空;401 未登录;404 文章不存在。

PUT /comments/{id} — 更新评论(需登录,仅作者)

参数:content(string,必填,新的评论内容)。成功:{"code": 200, "message": "评论更新成功", "data": null}。可能错误:400 评论ID无效或内容为空;403 无权修改此评论;404 评论不存在。

DELETE /comments/{id} — 删除评论(需登录,仅作者)

成功:{"code": 200, "message": "评论删除成功", "data": null}。可能错误同上。

POST /comments/{id}/like 与 POST /comments/{id}/unlike — 点赞 / 取消点赞评论(需登录)

成功分别返回 {"code": 200, "message": "点赞成功", "data": {"like_count": 2}} 与 {"code": 200, "message": "取消点赞成功", "data": {"like_count": 1}}。依赖「互动增强」插件。

5.5 分类接口

GET /categories — 分类列表

通用分页参数。元素字段:id、name、slug、description、keywords、parent_id、sort、is_menu、created_at。

GET /categories/{id} — 分类详情

可能错误:400 分类ID无效;404 分类不存在。

POST /categories — 创建分类(需管理员)

参数:name(string,必填,分类名称,最长 100 字符)、slug(string,可选,分类别名,缺省取名称)、description(string,可选,描述)、parent_id(int,可选,父分类 ID,默认 0)。成功:{"code": 200, "message": "分类创建成功", "data": {"category_id": 3}}。可能错误:400 参数校验失败;401 未登录;403 无权创建分类。

PUT /categories/{id} — 更新分类(需管理员)

字段均可选:name、slug、description、parent_id。成功:{"code": 200, "message": "分类更新成功", "data": null}。可能错误:403 无权修改分类;404 分类不存在。

DELETE /categories/{id} — 删除分类(需管理员)

成功:{"code": 200, "message": "分类删除成功", "data": null}。可能错误:403 无权删除分类;404 分类不存在。

5.6 标签接口

GET /tags — 标签列表

通用分页参数。元素字段:id、name、count(使用次数)、created_at。

GET /tags/{id} — 标签详情

可能错误:400 标签ID无效;404 标签不存在。

POST /tags — 创建标签(需管理员)

参数:name(string,必填,标签名称,最长 100 字符)。成功:{"code": 200, "message": "标签创建成功", "data": {"tag_id": 4}}。可能错误:400 参数校验失败;401 未登录;403 无权创建标签。

PUT /tags/{id} — 更新标签(需管理员)

可选字段:name。成功:{"code": 200, "message": "标签更新成功", "data": null}。可能错误:403 无权修改标签;404 标签不存在。

DELETE /tags/{id} — 删除标签(需管理员)

成功:{"code": 200, "message": "标签删除成功", "data": null}。可能错误:403 无权删除标签;404 标签不存在。

5.7 页面接口

GET /pages — 页面列表

通用分页参数。元素字段:id、title、content、description、keywords、slug、status、is_menu、created_at、updated_at。

GET /pages/{id} — 页面详情

可能错误:400 页面ID无效;404 页面不存在。

5.8 用户接口

GET /users — 用户列表

通用分页参数。元素为用户表行,节选字段:id、username、nickname、email、avatar、bio、website、role、status、created_at。

GET /users/{id} — 用户详情

字段同上。可能错误:400 用户ID无效;404 用户不存在。

POST /users — 注册用户

参数与 POST /auth/register 一致(username、password、email 必填,nickname 可选)。成功:{"code": 200, "message": "注册成功", "data": {"user_id": 6}}。可能错误:400 参数校验失败。

PUT /users/{id} — 更新用户(需登录,仅本人)

参数:id(int,必填,用户 ID,服务端从请求体读取,路径中的 id 不参与解析)、email(string,可选,新邮箱)、nickname(string,可选,新昵称)。成功:{"code": 200, "message": "更新成功", "data": null}。可能错误:400 用户ID无效;401 未登录;403 无权修改此用户。

DELETE /users/{id} — 删除用户(需登录,管理员)

id 同样从请求体读取。成功:{"code": 200, "message": "删除成功", "data": null}。可能错误:400 用户ID无效或不能删除自己;403 无权删除用户。

POST /users/{id}/follow — 关注用户(需登录)

成功:{"code": 200, "message": "关注成功", "data": null}。可能错误:400 用户ID无效或不能关注自己;401 未登录。依赖「互动增强」插件。

POST /users/{id}/unfollow — 取消关注(需登录)

成功:{"code": 200, "message": "取消关注成功", "data": null}。

GET /users/{id}/followers 与 GET /users/{id}/following — 粉丝列表 / 关注列表(需登录)

通用分页参数,分页响应。

GET /users/me/favorites、GET /users/me/likes、GET /users/me/history — 我的收藏 / 我的点赞 / 阅读历史(需登录)

通用分页参数,分页响应。依赖「互动增强」插件。

5.9 搜索接口

GET /search — 全局搜索

参数类型必填说明
keywordstring是搜索关键词
typestring否搜索类型:article(默认)、user、comment
pageint否页码
page_sizeint否每页数量

分页响应,items 内容随 type 变化。可能错误:400 搜索关键词不能为空。

5.10 上传接口(需登录会话)

均为 multipart/form-data 请求。

POST /upload/image — 上传图片

参数类型必填说明
imagefile是图片文件,支持 JPG/PNG/GIF/WEBP,不超过 5MB
{"code": 200, "message": "上传成功", "data": {"url": "/uploads/images/2026/10/09/image_1760000000_1234.png", "filename": "image_1760000000_1234.png", "size": 102400}}

可能错误:400 图片上传失败、格式不支持、大小超限。

POST /upload/file — 上传文件

参数:file(file,必填,支持 PDF/Word/Excel/ZIP/RAR,不超过 20MB)。响应 data 同图片接口(url、filename、size),url 形如 /uploads/files/2026/10/09/file_xxx.pdf。

POST /upload/avatar — 上传头像(需登录会话)

参数:avatar(file,必填,图片文件,支持 JPG/PNG/GIF/WEBP,不超过 2MB)。成功后同时更新当前用户头像。

{"code": 200, "message": "头像上传成功", "data": {"url": "/uploads/avatars/avatar_1_1760000000.png", "filename": "avatar_1_1760000000.png"}}

5.11 通知接口(需登录会话)

依赖「消息通知」插件。

GET /notifications — 通知列表

通用分页参数,分页响应。

GET /notifications/unread — 未读数量

{"code": 200, "message": "获取成功", "data": {"unread_count": 3}}

PUT /notifications/{id}/read — 标记通知已读

路径参数 id。成功:{"code": 200, "message": "标记成功", "data": null}。可能错误:400 通知ID无效;403 无权操作此通知;404 通知不存在。

PUT /notifications/read-all — 全部标记已读

无参数。成功:{"code": 200, "message": "全部标记成功", "data": null}。

6. 钩子扩展

开放 API 不提供对外推送(Webhook)。API 处理生命周期中会触发系统内部钩子,其他插件可监听这些钩子介入流程:

钩子触发时机携带数据
api_request_before请求分发前path、method、params
api_response_before控制器返回后、输出前path、method、result
api_response_after响应输出后path、method
api_error控制器抛出异常时path、method、error、trace

插件的钩子注册方式见 插件开发指南。

7. 常见问题

跨域(CORS)

后台「API 设置」中开启「启用CORS跨域支持」后,入口层输出 Access-Control-Allow-Origin(来源由「允许的跨域来源」控制,默认 *)等响应头,并对 OPTIONS 预检请求直接返回。未开启时,浏览器跨域调用会被拦截;小程序、原生 App 的服务端请求不受 CORS 限制。

密钥泄露处理

发现密钥泄露时,立即在后台该插件的密钥管理中「撤销」对应密钥(状态置为 inactive,之后请求返回 401「API Key已被撤销」),排查影响范围后新建密钥。建议为每个客户端应用分配独立密钥,并配置 IP 白名单与过期时间;密钥明文仅在创建时展示一次,无法再次查看。

限流

开放 API 提供两级限流:全局限流在后台「API 设置」中开启「启用请求频率限制」,按客户端 IP 以固定时间窗口计数(次数与窗口大小均可配置),触发后返回 429「请求过于频繁,请稍后重试」;密钥级限流按创建或编辑密钥时设置的次数、时间窗口与单位(秒/分/时/天)计数,超出后该密钥的校验失败,返回 403「API Key请求频率超过限制」。