🔧 Qexo API完全使用指南
📖 API概述
🎯 核心特性
Qexo Public API 提供了一套RESTful风格的HTTP接口,用于博客内容管理、友链管理、说说管理、统计数据等功能。
🌐 基础URL
1
| https://your-qexo-domain.com/pub/
|
🔐 鉴权说明
1️⃣ 获取API Token
登录 Qexo 管理面板,进入 设置 > API配置 生成或查看您的 API Key
2️⃣ 使用Token
在需要鉴权的接口中,通过以下方式传递token:
GET请求
POST请求
📋 图标说明
| 图标 |
说明 |
| 🔒 |
需要Token鉴权 |
| 🌐 |
公开访问,无需鉴权 |
| 🤖 |
需要reCAPTCHA人机验证 |
📑 API分类
🗂️ 内容管理API
- 保存文件内容
- 删除文件
- 创建Webhook
- 获取文章列表
- 获取页面列表
- 获取配置文件列表
- 获取图片列表
- 自动修复配置
👥 友链管理API
- 获取公开友链
- 获取全部友链
- 新增友链
- 编辑友链
- 删除友链
- 申请友链
💬 说说管理API
- 获取说说列表
- 点赞说说
- 保存说说
- 删除说说
- 获取全部说说
🎨 自定义字段API
- 获取自定义字段
- 编辑自定义字段
- 删除自定义字段
- 新建自定义字段
📊 通知与统计API
- 获取通知列表
- 获取博客状态
- 页面访问统计
- 创建自定义通知
🗂️ 内容管理API详解
1️⃣ 保存文件内容 🔒
端点
描述
保存或更新文件内容到Git Provider
请求参数
1 2 3 4 5 6
| { "token": "your_api_token", "file": "source/_posts/my-article.md", "content": "# 文章标题\n\n文章内容...", "commitchange": "Update article" }
|
响应示例
1 2 3 4
| { "msg": "保存成功!", "status": true }
|
curl示例
1 2 3 4
| curl -X POST https://your-domain.com/pub/save \ -d "token=your_token" \ -d "file=source/_posts/test.md" \ -d "content=Hello World"
|
2️⃣ 删除文件 🔒
端点
描述
从Provider删除指定文件
请求参数
1 2 3 4 5
| { "token": "your_api_token", "file": "source/_posts/old-article.md", "commitchange": "Delete old article" }
|
响应示例
1 2 3 4
| { "msg": "删除成功并提交部署!", "status": true }
|
3️⃣ 创建Webhook 🔒
端点
1
| POST /pub/create_webhook
|
描述
自动配置Git Provider的Webhook
请求参数
1 2 3 4
| { "token": "your_api_token", "uri": "https://your-domain.com/api/webhook" }
|
响应示例
1 2 3 4 5 6
| { "msg": "Webhook创建成功!", "status": true, "token": "generated_webhook_token", "webhook_url": "https://your-domain.com/api/webhook?token=xxx" }
|
4️⃣ 获取文章列表 🔒
端点
描述
获取所有文章列表
请求参数
| 参数 |
类型 |
必需 |
说明 |
| token |
string |
是 |
API Token |
| s |
string |
否 |
搜索关键词 |
响应示例
1 2 3 4 5 6 7 8 9 10 11 12
| { "status": true, "posts": [ { "name": "我的第一篇文章", "path": "source/_posts/my-first-post.md", "fullname": "source/_posts/my-first-post.md", "size": 1024, "date": "2026-01-07 10:30:00" } ] }
|
curl示例
1
| curl "https://your-domain.com/pub/get_posts?token=your_token&s=关键词"
|
5️⃣ 获取页面列表 🔒
端点
描述
获取所有独立页面列表
请求参数
| 参数 |
类型 |
必需 |
说明 |
| token |
string |
是 |
API Token |
| s |
string |
否 |
搜索关键词 |
响应格式
与 get_posts 相同
6️⃣ 获取配置文件列表 🔒
端点
描述
获取所有配置文件列表
请求参数
| 参数 |
类型 |
必需 |
说明 |
| token |
string |
是 |
API Token |
| s |
string |
否 |
搜索关键词 |
响应格式
与 get_posts 相同
7️⃣ 获取图片列表 🔒
端点
描述
获取所有上传的图片记录
请求参数
| 参数 |
类型 |
必需 |
说明 |
| token |
string |
是 |
API Token |
| s |
string |
否 |
搜索关键词 |
响应示例
1 2 3 4 5 6 7 8 9 10 11 12
| { "status": true, "images": [ { "name": "avatar.png", "size": "125.6 KB", "url": "https://cdn.example.com/avatar.png", "date": "2026-01-07 10:30:00", "time": "1704599400" } ] }
|
8️⃣ 自动修复配置 🔒
端点
描述
自动检测并修复系统配置问题
请求参数
1 2 3
| { "token": "your_api_token" }
|
响应示例
1 2 3 4
| { "msg": "尝试自动修复了 5 个字段,请在稍后检查和修改配置", "status": true }
|
👥 友链管理API详解
9️⃣ 获取公开友链 🌐
端点
描述
获取所有公开显示的友情链接(无需鉴权)
请求参数
无
响应示例
1 2 3 4 5 6 7 8 9 10 11 12
| { "data": [ { "name": "张三的博客", "url": "https://zhangsan.com", "image": "https://zhangsan.com/avatar.jpg", "description": "一个热爱技术的程序员", "time": "1704599400" } ], "status": true }
|
curl示例
1
| curl "https://your-domain.com/pub/friends"
|
⚠️ 向后兼容:此接口保持原有响应格式
🔟 获取全部友链 🔒
端点
描述
获取所有友链(包括隐藏的,需要鉴权)
请求参数
| 参数 |
类型 |
必需 |
说明 |
| token |
string |
是 |
API Token |
| s |
string |
否 |
搜索关键词 |
响应示例
1 2 3 4 5 6 7 8 9 10 11 12 13
| { "data": [ { "name": "张三的博客", "url": "https://zhangsan.com", "image": "https://zhangsan.com/avatar.jpg", "description": "一个热爱技术的程序员", "time": "1704599400", "status": true } ], "status": true }
|
⚠️ 向后兼容:此接口保持原有响应格式
1️⃣1️⃣ 新增友链 🔒
端点
描述
添加新的友情链接
请求参数
1 2 3 4 5 6 7 8
| { "token": "your_api_token", "name": "李四的博客", "url": "https://lisi.com", "image": "https://lisi.com/avatar.jpg", "description": "专注前端开发", "status": "显示" }
|
响应示例
1 2 3 4 5
| { "msg": "添加成功!", "time": "1704599400", "status": true }
|
1️⃣2️⃣ 编辑友链 🔒
端点
描述
编辑现有友情链接
请求参数
1 2 3 4 5 6 7 8 9
| { "token": "your_api_token", "time": "1704599400", "name": "李四的新博客", "url": "https://new-lisi.com", "image": "https://new-lisi.com/avatar.jpg", "description": "全栈工程师", "status": "显示" }
|
响应示例
1 2 3 4
| { "msg": "修改成功!", "status": true }
|
1️⃣3️⃣ 删除友链 🔒
端点
描述
删除指定友情链接
请求参数
1 2 3 4
| { "token": "your_api_token", "time": "1704599400" }
|
响应示例
1 2 3 4
| { "msg": "删除成功!", "status": true }
|
1️⃣4️⃣ 申请友链 🤖
端点
描述
公开的友链申请接口(需要reCAPTCHA验证)
请求参数
1 2 3 4 5 6 7
| { "name": "王五的博客", "url": "https://wangwu.com", "image": "https://wangwu.com/avatar.jpg", "description": "技术分享", "verify": "recaptcha_response_token" }
|
响应示例
1 2 3 4 5
| { "msg": "申请成功!", "time": "1704599400", "status": true }
|
注意事项
- 需要在Qexo设置中启用友链申请功能
- 需要配置reCAPTCHA (v2或v3)
- 申请的友链默认为隐藏状态,需管理员审核
⚠️ 向后兼容:此接口保持原有响应格式
💬 说说管理API详解
1️⃣5️⃣ 获取说说列表 🌐
端点
描述
获取说说列表(分页,无需鉴权)
请求参数
| 参数 |
类型 |
必需 |
说明 |
| page |
integer |
否 |
页码,默认1 |
| limit |
integer |
否 |
每页数量,默认5 |
响应示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| { "msg": "获取成功!", "status": true, "count": 50, "data": [ { "id": "550e8400-e29b-41d4-a716-446655440000", "content": "今天天气真不错!", "time": "1704599400", "tags": ["生活", "随笔"], "like": 5, "liked": false, "values": {"location": "北京"} } ] }
|
curl示例
1
| curl "https://your-domain.com/pub/talks?page=1&limit=10"
|
⚠️ 向后兼容:此接口保持原有响应格式
1️⃣6️⃣ 点赞说说 🌐
端点
描述
点赞/取消点赞说说(通过IP防止重复点赞)
请求参数
1 2 3
| { "id": "550e8400-e29b-41d4-a716-446655440000" }
|
响应示例
1 2 3 4 5
| { "msg": "点赞成功!", "action": true, "status": true }
|
⚠️ 向后兼容:此接口保持原有响应格式
1️⃣7️⃣ 保存说说 🔒
端点
描述
创建或编辑说说
请求参数(新建)
1 2 3 4 5 6
| { "token": "your_api_token", "content": "今天天气真不错!", "tags": "[\"生活\", \"随笔\"]", "values": "{\"location\": \"北京\"}" }
|
请求参数(编辑)
1 2 3 4 5 6 7 8
| { "token": "your_api_token", "id": "550e8400-e29b-41d4-a716-446655440000", "content": "更新后的内容", "tags": "[\"生活\"]", "time": "1704599400", "values": "{}" }
|
响应示例(新建)
1 2 3 4 5
| { "msg": "保存成功!", "status": true, "id": "550e8400-e29b-41d4-a716-446655440000" }
|
响应示例(编辑)
1 2 3 4
| { "msg": "修改成功!", "status": true }
|
1️⃣8️⃣ 删除说说 🔒
端点
描述
删除指定说说
请求参数
1 2 3 4
| { "token": "your_api_token", "id": "550e8400-e29b-41d4-a716-446655440000" }
|
响应示例
1 2 3 4
| { "msg": "删除成功!", "status": true }
|
1️⃣9️⃣ 获取全部说说 🔒
端点
描述
获取所有说说(管理用,带搜索)
请求参数
| 参数 |
类型 |
必需 |
说明 |
| token |
string |
是 |
API Token |
| s |
string |
否 |
搜索关键词 |
响应示例
1 2 3 4 5 6 7 8 9 10 11 12 13
| { "msg": "获取成功!", "status": true, "data": [ { "content": "今天天气真不错!...", "tags": "生活, 随笔", "time": "2026-01-07 10:30:00", "like": 5, "id": "550e8400-e29b-41d4-a716-446655440000" } ] }
|
🎨 自定义字段API详解
2️⃣0️⃣ 获取自定义字段 🔒
端点
1
| GET/POST /pub/get_custom
|
描述
获取并执行自定义字段内容(使用RestrictedPython沙箱)
安全特性
- ✅ 强制Token鉴权
- ✅ RestrictedPython 8.1 专业沙箱环境
- ✅ 记录所有执行日志和错误
- ✅ 自动编译时安全检查
- ⚠️ 禁止访问文件系统、网络和危险操作
请求参数
1 2 3 4 5 6
| { "token": "your_api_token", "key": "custom_field_name", "param1": "value1", "param2": "value2" }
|
响应示例
1 2 3 4
| { "data": "执行结果输出", "status": true }
|
沙箱环境说明
使用 RestrictedPython 提供沙箱:
| 特性 |
说明 |
limited_builtins |
受限的内置函数集 |
utility_builtins |
实用工具函数(safe_iter, safe_range等) |
safe_globals |
安全的全局变量集 |
额外提供
安全限制
- ❌ 不允许
open, eval, exec, compile, __import__
- ❌ 不允许访问
__ 开头的特殊属性
- ❌ 不允许导入任意模块
- ✅ 仅允许安全的数据操作和运算
示例代码
1 2 3 4 5 6 7 8 9
| result = sum([1, 2, 3, 4, 5]) data = {"name": param1, "value": int(param2)} print(json.dumps(data))
import os open('/etc/passwd') __import__('subprocess')
|
2️⃣1️⃣ 编辑自定义字段 🔒
端点
描述
编辑或创建自定义字段
请求参数
1 2 3 4 5
| { "token": "your_api_token", "name": "my_custom_field", "content": "print('Hello World')" }
|
响应示例
1 2 3 4
| { "msg": "保存成功!", "status": true }
|
2️⃣2️⃣ 删除自定义字段 🔒
端点
描述
删除指定自定义字段
请求参数
1 2 3 4
| { "token": "your_api_token", "name": "my_custom_field" }
|
响应示例
1 2 3 4
| { "msg": "删除成功!", "status": true }
|
2️⃣3️⃣ 新建自定义字段 🔒
端点
描述
新建自定义字段(功能同 set_custom)
请求参数
同 set_custom
响应示例
同 set_custom
📊 通知与统计API详解
2️⃣4️⃣ 获取通知列表 🔒
端点
1
| GET /pub/get_notifications
|
描述
获取所有系统通知
请求参数
1 2 3
| { "token": "your_api_token" }
|
响应示例
1 2 3 4 5 6 7 8 9 10
| { "data": [ { "label": "友链申请 张三的博客", "content": "站点名: 张三的博客<br>链接: https://zhangsan.com<br>...", "time": "1704599400" } ], "status": true }
|
2️⃣5️⃣ 获取博客状态 🌐
端点
描述
获取博客基本信息(无需鉴权)
请求参数
无
响应示例
1 2 3 4 5 6 7
| { "data": { "posts": "42", "last": "2026-01-07 10:30:00" }, "status": true }
|
⚠️ 向后兼容:此接口保持原有响应格式
2️⃣6️⃣ 页面访问统计 🌐
端点
描述
记录并返回页面访问统计(需域名白名单)
请求要求
- 必须从配置的允许域名发起请求
- 通过 HTTP_REFERER 头识别来源
响应示例
1 2 3 4 5 6
| { "site_pv": 1250, "page_pv": 45, "site_uv": 320, "status": true }
|
配置要求
⚠️ 向后兼容:此接口保持原有响应格式
2️⃣7️⃣ 创建自定义通知 🔒
端点
描述
创建自定义通知消息
请求参数(JSON Body)
1 2 3 4
| { "title": "系统维护通知", "content": "系统将于今晚22:00进行维护,预计持续1小时。" }
|
请求头
1
| Content-Type: application/json
|
响应示例
1 2 3 4
| { "msg": "添加成功!", "status": true }
|
curl示例
1 2 3 4
| curl -X POST https://your-domain.com/pub/notifications \ -H "Content-Type: application/json" \ -d '{"title":"测试通知","content":"这是一条测试通知"}' \ -d "token=your_token"
|
📋 错误处理
标准错误响应
所有API在出错时返回统一格式:
1 2 3 4
| { "msg": "错误描述信息", "status": false }
|
常见错误码
| HTTP状态码 |
说明 |
| 200 |
成功(检查响应中的status字段) |
| 403 |
鉴权失败或权限不足 |
| 500 |
服务器内部错误 |
常见错误信息
| 错误信息 |
原因 |
解决方案 |
| “鉴权错误!” |
Token无效或未提供 |
检查Token是否正确 |
| “人机验证失败!” |
reCAPTCHA验证失败 |
重新获取验证token |
| “域名未验证” |
统计API域名不在白名单 |
在设置中添加域名 |
| “平台不支持” |
Provider不支持该操作 |
检查Provider配置 |
🔄 迁移指南(v1.x → v2.0)
重大变更
所有需鉴权的接口都需要显式传递token
- ❌ 旧版:部分接口可能不需要token
- ✅ 新版:统一使用
@api_auth_required装饰器
响应消息国际化
- ❌ 旧版:硬编码中文消息
- ✅ 新版:支持多语言,根据系统语言设置返回
错误响应格式统一
所有错误响应都包含status: false字段
get_custom 安全大幅增强
- ❌ 旧版:无鉴权,可执行任意代码,极度危险
- ✅ 新版:强制Token鉴权 + RestrictedPython 8.1 专业沙箱
- ✅ 新增:编译时安全检查,运行时隔离环境
⚠️ 重要:需要安装 RestrictedPython==8.1 依赖
环境要求
新增依赖:
1
| pip install RestrictedPython==8.1
|
或更新 requirements.txt / Pipfile 后重新安装。
保持兼容的接口
以下接口完全保持原有响应格式,无需修改调用代码:
GET /pub/friends
GET /pub/get_friends
POST /pub/ask_friend
GET /pub/talks
POST /pub/like_talk
GET /pub/status
GET /pub/statistic
需要调整的接口
示例:save接口
旧版调用:
1 2
| response = requests.post("/pub/save", data={"file": "...", "content": "..."})
|
新版调用:
1 2 3 4 5 6 7 8 9
| response = requests.post("/pub/save", data={ "token": "your_token", "file": "...", "content": "..." }) result = response.json() if result.get("status"): print(result.get("msg"))
|
📝 最佳实践
1. Token安全
1 2 3 4 5 6
| import os TOKEN = os.environ.get("QEXO_API_TOKEN")
TOKEN = "my_secret_token_123"
|
2. 错误处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import requests
def call_qexo_api(endpoint, data): try: response = requests.post( f"https://your-domain.com/pub/{endpoint}", data=data, timeout=10 ) response.raise_for_status() result = response.json() if not result.get("status"): raise Exception(f"API错误: {result.get('msg')}") return result except requests.exceptions.RequestException as e: print(f"请求失败: {e}") return None
|
3. 批量操作
1 2 3 4 5 6 7 8
| posts = [] for keyword in ["Python", "Django", "API"]: response = requests.get( f"https://your-domain.com/pub/get_posts", params={"token": TOKEN, "s": keyword} ) posts.extend(response.json().get("posts", []))
|
🚀 快速开始示例
Python示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| import requests import json
BASE_URL = "https://your-qexo-domain.com/pub" TOKEN = "your_api_token"
def get_posts(): response = requests.get(f"{BASE_URL}/get_posts", params={"token": TOKEN}) return response.json()
def create_talk(content, tags): data = { "token": TOKEN, "content": content, "tags": json.dumps(tags), "values": "{}" } response = requests.post(f"{BASE_URL}/save_talk", data=data) return response.json()
def apply_friend_link(name, url, image, description, recaptcha_token): data = { "name": name, "url": url, "image": image, "description": description, "verify": recaptcha_token } response = requests.post(f"{BASE_URL}/ask_friend", data=data) return response.json()
if __name__ == "__main__": posts = get_posts() print(f"共有 {len(posts.get('posts', []))} 篇文章") result = create_talk("今天学习了Qexo API!", ["技术", "学习"]) if result.get("status"): print(f"说说创建成功,ID: {result.get('id')}")
|
JavaScript示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| const BASE_URL = 'https://your-qexo-domain.com/pub'; const TOKEN = 'your_api_token';
async function getFriends() { const response = await fetch(`${BASE_URL}/friends`); const data = await response.json(); return data.data; }
async function likeTalk(talkId) { const formData = new FormData(); formData.append('id', talkId); const response = await fetch(`${BASE_URL}/like_talk`, { method: 'POST', body: formData }); return await response.json(); }
async function saveFile(filePath, content) { const formData = new FormData(); formData.append('token', TOKEN); formData.append('file', filePath); formData.append('content', content); const response = await fetch(`${BASE_URL}/save`, { method: 'POST', body: formData }); return await response.json(); }
getFriends().then(friends => { console.log(`共有 ${friends.length} 个友链`); friends.forEach(friend => { console.log(`- ${friend.name}: ${friend.url}`); }); });
|
🔗 相关链接
📚 总结
Qexo API 提供了完整的博客管理功能,通过RESTful接口实现了:
✅ 核心功能
- ✅ 内容管理(文章、页面、配置)
- ✅ 友链管理(增删改查)
- ✅ 说说管理(发布、点赞、评论)
- ✅ 自定义字段(安全沙箱)
- ✅ 统计分析(访问量、用户数)
🎯 使用建议
- 妥善保管API Token
- 合理使用缓存机制
- 注意错误处理和重试
- 遵循最佳实践编写代码
💡 提示:建议在实际项目中进行充分的测试,确保API调用的稳定性和安全性。