Appearance
Webhook 模式(HTTP 回调)
与 WebSocket 网关二选一(bot.mode)。mode: webhook 时机器人不建立出站长连接,改为启动本地 HTTP 服务,由 QQ 开放平台把事件 POST 推送到回调地址。
适合无法维持出站长连接的场景。回调地址需公网可达,开放平台通过 HTTPS 访问它(HTTPS 的提供方式见 部署要求,框架本身不强制任何方案)。
工作原理
开放平台 ──POST 回调地址(HTTPS)──> HTTPS 入口 ──> Bngeuit HttpServer(host:port/path)
│(反向代理 / 内网穿透 / 直接监听,均可选)
├─ op=13 回调地址验证 → 返回签名完成验证
└─ op=0 事件推送 → 分发到 EventBus + 回包 op=12 ACK事件 payload 结构与 WebSocket DISPATCH 相同({id, op:0, d, s, t}),分发路径与 WebSocket 模式完全一致(同一 ConnectionState → EventBus)——插件无需感知接入方式差异。
回调地址验证(op=13)
在开放平台配置回调地址时,平台发起验证请求。框架用 appSecret 确定性派生的 Ed25519 私钥对 d.event_ts + d.plain_token 计算签名,原样返回 plain_token 与签名完成验证(与官方 Go 示例输出逐字节一致,已用单测锁定)。
事件请求签名校验(X-Signature-Ed25519)
每个事件推送(op=0)默认校验:
- 请求头
X-Signature-Ed25519(hex 64 字节签名) +X-Signature-Timestamp(时间戳) - 签名体 = 时间戳字符串 + 原始请求体字节
- 公钥 = appSecret 派生的 Ed25519 公钥
- 校验失败返回 401 拒绝处理
配置 webhook.verifySignature: false 可关闭(仅调试用,生产必须开启)。
配置
yaml
bot:
mode: webhook # 切换为 webhook 接入
webhook:
host: "0.0.0.0" # 回调监听地址
port: 8080 # 回调监听端口(官方限定 80/443/8080/8443)
path: "/" # 回调路径(必须以 / 开头)
verifySignature: true # 校验事件请求签名(默认 true)部署要求
- 端口:官方限定 80 / 443 / 8080 / 8443
- HTTPS 必选:开放平台要求回调地址为 HTTPS。框架不关心 TLS 在哪一层终止——常用方式:
- 反向代理(nginx / Caddy 等)把公网 HTTPS 转发到本机监听端口
- 内网穿透(frp / cloudflared 等)把公网域名映射到本机
- 直接让 Bngeuit 监听公网端口并提供证书(如监听 443)
- 回调地址:开放平台填写的回调地址 =
https://<公网域名或IP><path>,与webhook.path必须一致;配置一次即固定,重启无需重配 - 安全建议:前面有本地反向代理/穿透时,
host可锁127.0.0.1只让本机入口访问;直接暴露公网端口时保持0.0.0.0,依靠签名校验(verifySignature: true)防止伪造请求
与 WebSocket 模式的差异
| 维度 | WebSocket | Webhook |
|---|---|---|
| 连接方向 | 出站长连接(主动连网关) | 入站 HTTP 回调(被动收推送) |
| 分片(shard) | 支持多分片 | 无分片(单一回调地址) |
| 断线重连 | 框架自动重连(RESUME 补消息) | 平台侧负责推送重试 |
| 就绪事件 | 网关真实 READY 触发 ReadyEvent | 回调服务启动后触发 WebhookReadyEvent |
| 接入鉴权 | access_token(IDENTIFY/RESUME) | appSecret 派生 Ed25519 签名 |
| 回复消息 | 走 REST API(需 access_token) | 同左——回复消息仍需 access_token |
就绪信号(WebhookReadyEvent / onActive)
READY / RESUMED 是 QQ 开放平台 WebSocket 网关专属的系统事件(官方「通用数据结构」),Webhook 模式没有网关连接、平台也不会推送这两个事件。框架不会伪造 ReadyEvent,而是:
- 事件形式:回调服务启动完成后分发一次
WebhookReadyEvent(event/receive/,仅 Webhook 模式触发),事件监听器 / 脚本可用@SubscribeEvent/bngeuit.on('WebhookReadyEvent', ...)监听 - 插件推荐方式:实现
Plugin.onActive()—— 该生命周期在两种接入模式统一触发一次(WS 全部分片就绪 / Webhook 回调服务就绪),做「机器人已上线」初始化无需关心接入方式
java
// 插件:两种模式通用的「机器人上线」时机
@Override
public void onActive() {
startScheduledTasks(); // 启动定时推送等
}实现要点(零第三方依赖)
- HTTP 服务基于 JDK 内置
com.sun.net.httpserver.HttpServer,2 线程 daemon 回调池,事件处理不阻塞回调线程(EventBus 异步分发) - Ed25519 签名/校验使用纯 Java 实现(RFC 8032)与 JDK 内置实现,无第三方库
