d4962a840da732812c72c7ff8f3fb4f4db8259d9
- 将 COMMAND_LENGTH 拆分为 COMMAND_LENGTH_MIN 和 COMMAND_LENGTH_MAX - 正则匹配支持 2~4 个中文字,范围通过 .env 配置 - 默认最小 2 字、最大 4 字
Webhook Plugin
NcatBot 插件,对外暴露 HTTP 接口,接收外部消息转发至 QQ。
功能特性
- 发送群消息 / 私聊消息(文本、图片、文件、视频)
- 批量发送消息,自动组合消息段
- 文件上传接口,支持本地文件发送
- API Key 鉴权,未配置时自动生成随机密钥
- 上传文件自动清理(超过 24 小时删除)
- 完善的错误处理与重试机制
快速开始
# 安装依赖
uv sync
# 复制环境变量模板
cp .env.example .env
# 编辑 .env 配置(可选,不设置 API_KEY 会自动生成)
vim .env
# 启动 NcatBot
uv run python -m ncatbot
启动后日志会打印 WEBHOOK_API_KEY,未配置时为自动生成的 UUID。
环境变量
| 变量 | 必填 | 默认值 | 说明 |
|---|---|---|---|
WEBHOOK_API_KEY |
否 | 自动生成 | API 鉴权密钥,未设置时自动生成 UUIDv4 |
WEBHOOK_HOST |
否 | 0.0.0.0 |
监听地址 |
WEBHOOK_PORT |
否 | 8081 |
监听端口 |
UPLOAD_DIR |
否 | ./uploads |
上传文件保存目录 |
MAX_UPLOAD_SIZE |
否 | 20971520 |
单文件最大字节数(默认 20 MB) |
ALLOWED_EXTENSIONS |
否 | 空(不限) | 允许的扩展名,逗号分隔,如 jpg,png,pdf |
QQ_API_TIMEOUT |
否 | 10 |
QQ API 超时秒数 |
QQ_API_MAX_RETRIES |
否 | 2 |
QQ API 失败重试次数 |
COMMAND_PREFIX |
否 | # |
命令前缀 |
COMMAND_LENGTH |
否 | 4 |
命令名字符数(中文字数) |
COMMAND_CALLBACK_URL |
否 | 空(不监听) | 命令匹配后的回调 URL |
接口说明
所有接口响应格式统一:
// 成功
{"code": 0, "msg": "ok", "data": {...}}
// 失败
{"code": 400, "msg": "invalid json", "data": null}
鉴权方式(除 /healthz 外必填):
Authorization: Bearer <API_KEY>
# 或
X-API-Key: <API_KEY>
GET /healthz
健康检查,无需鉴权。
响应:
{"code": 0, "msg": "ok", "data": {"health": "ok"}}
POST /upload
上传文件到服务器,返回文件 ID 供后续消息引用。
请求: multipart/form-data,字段名不限,带 filename 即可。
响应:
{
"code": 0,
"msg": "ok",
"data": {
"files": ["document.pdf", "photo.jpg"],
"path": "document.pdf"
}
}
files:所有上传文件的相对路径(文件 ID)path:单文件上传时的快捷字段
上传的文件超过 24 小时会被自动清理。
POST /webhook
发送 QQ 消息,支持单条和批量两种模式。
单条发送
请求:
{
"group_id": "123456789",
"type": "text",
"msg": "Hello!"
}
| 字段 | 必填 | 说明 |
|---|---|---|
group_id |
二选一 | 群号 |
user_id |
二选一 | QQ 号(私聊) |
type |
否 | 消息类型:text(默认)、image、file、video |
msg |
text 时必填 | 文本内容 |
url |
image/file/video 时必填 | 资源链接或上传返回的文件 ID |
示例:
# 发送文本
curl -X POST http://localhost:8081/webhook \
-H "Content-Type: application/json" \
-H "X-API-Key: your-key" \
-d '{"group_id": "123456789", "type": "text", "msg": "Hello!"}'
# 发送图片(URL)
curl -X POST http://localhost:8081/webhook \
-H "Content-Type: application/json" \
-H "X-API-Key: your-key" \
-d '{"group_id": "123456789", "type": "image", "url": "https://example.com/photo.jpg"}'
# 发送文件(本地已上传)
curl -X POST http://localhost:8081/webhook \
-H "Content-Type: application/json" \
-H "X-API-Key: your-key" \
-d '{"group_id": "123456789", "type": "file", "url": "document.pdf"}'
批量发送
使用 messages 数组批量发送多条消息。text、image、video 会组合成一条消息发送(框架自动处理冲突拆分),file 每条单独发送。
请求:
{
"group_id": "123456789",
"messages": [
{"type": "text", "msg": "文件已发送"},
{"type": "image", "url": "preview.jpg"},
{"type": "file", "url": "document.pdf"},
{"type": "video", "url": "demo.mp4"}
]
}
响应:
{
"code": 0,
"msg": "ok",
"data": {
"total": 4,
"success": 4,
"failed": 0,
"results": [
{"index": 0, "success": true},
{"index": 1, "success": true},
{"index": 2, "success": true},
{"index": 3, "success": true}
]
}
}
每条消息独立处理,一条失败不影响其他消息。results 数组按原始 index 排序,包含每条消息的发送结果。
命令监听
插件会自动监听 QQ 消息,当消息以 #四个中文字+空格 开头时,将命令内容 POST 到 COMMAND_CALLBACK_URL。
匹配规则:
#测试命令 你好世界
│ │ │ │
│ │ │ └── 命令内容(content)
│ └── 空格分隔
└── 命令名(4个中文字)
└── 前缀(默认 #)
- 前缀、命令名长度可通过
COMMAND_PREFIX、COMMAND_LENGTH配置 - 不配置
COMMAND_CALLBACK_URL则不监听
回调请求体(POST JSON):
{
"command": "测试命令",
"content": "你好世界",
"raw_message": "#测试命令 你好世界",
"user_id": "123456",
"group_id": "789012",
"message_id": "abc123"
}
| 字段 | 说明 |
|---|---|
command |
命令名(4个中文字) |
content |
命令后的内容 |
raw_message |
原始消息文本 |
user_id |
发送者 QQ 号 |
group_id |
群号(私聊消息无此字段) |
message_id |
消息 ID |
回调响应格式(自动回复到 QQ):
回调服务器返回 JSON,插件会自动将内容回复到原消息来源(群/私聊)。
纯文本回复:
{"reply": "收到你的命令了"}
批量回复(text/image/video 组合发送,file 单独发送):
{
"messages": [
{"type": "text", "msg": "处理结果如下"},
{"type": "image", "url": "https://example.com/result.png"},
{"type": "file", "url": "report.pdf"}
]
}
| 字段 | 说明 |
|---|---|
reply |
纯文本回复(与 messages 二选一,messages 优先) |
messages |
批量回复数组,格式同 /webhook 的 messages 字段 |
group_id |
可选,覆盖回复目标群号(默认回复到原群) |
user_id |
可选,覆盖回复目标 QQ 号(默认回复到原发送者) |
不需要回复时返回 {} 或空响应即可。
项目结构
├── plugin.py # 插件入口,组装并启动 HTTP 服务
├── config.py # 配置(环境变量)
├── middleware.py # 鉴权 & 请求 ID 中间件
├── response.py # 统一响应格式
├── handlers/
│ ├── __init__.py
│ ├── command.py # 命令监听匹配与回调
│ ├── health.py # GET /healthz
│ ├── message.py # POST /webhook
│ └── upload.py # POST /upload
├── manifest.toml # NcatBot 插件元数据
├── .env.example # 环境变量模板
└── pyproject.toml # Python 依赖声明
部署建议
- 放在 Nginx/Caddy 反向代理后,启用 HTTPS
- 配置请求限流,防止滥用
- 使用 systemd 管理进程:
# /etc/systemd/system/ncatbot.service
[Unit]
Description=NcatBot Webhook Plugin
After=network.target
[Service]
Type=simple
User=ncatbot
WorkingDirectory=/opt/ncatbot
EnvironmentFile=/opt/ncatbot/.env
ExecStart=/opt/ncatbot/.venv/bin/python -m ncatbot
Restart=on-failure
[Install]
WantedBy=multi-user.target
日志默认输出到 stdout,可由 journald 收集查看:
journalctl -u ncatbot -f
Description
Languages
Python
100%