Webhook 满天飞的时代,我用一个面板做"通知收口"

69 阅读 2435 字 · 约 9 分钟

0. 引子

最开始只是几行 GitHub 通知——我维护几个 repo 想第一时间知道 star / PR / CI。后来给 Kimi 加任务结束通知,再后来自己搭监控,磁盘、Cron、证书过期都要告警。4 个工具、4 个 webhook、4 个 key,散落在 4 个地方。

再往后事情失控:渠道从 Bark 切到飞书(iPhone + Mac),飞书里又分 A 群 B 群 C 群,国际项目准备切 Slack,告警风暴时有发生……到这一步我才意识到问题不在"用哪个渠道",而在信息源和分发渠道都在我代码里。

我决定自己写一个——叫 Bluebird,把散落的 webhook 收在一起,配置和查看都在一个面板里。


1. 痛点:双线散落

故事里的痛点其实是普遍现象:信息源侧散落(每个工具单独配推送目标)+ 分发侧散落(key 散落在脚本 / CI / Prometheus 等各处),衍生四个具体问题——改接收人难、临时静音难、失败审计难、多渠道分发难。


2. 思路:二段抽象

既然痛点是"两端都散落",解法就是两端都集中:

信息源经 Bluebird 通知网关分发到多渠道

  • 信息源:每类应用做一层适配,统一成"带认证的 HTTP 端点 + 字段映射 + 事件过滤";
  • 分发渠道:每种渠道做成实例,密钥和接收人都集中在面板里,改接收人不改脚本。

两段之间靠矩阵挂钩——"哪些源走哪些渠道"在面板里勾,改完即生效。


3. 信息源与分发侧

通用 HTTP——任何能发 POST 的应用都能用:

curl -X POST https://你的域名/hooks/<来源 ID> \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"title":"备份完成","body":"server-01 ok","event":"backup"}'

GitHub 适配层内置(不需要 Actions),HMAC 校验、按事件类型过滤、本人操作过滤、卡片渲染都在面板里开关。新增一类信息源(GitLab / Sentry / Grafana),在 server.py 加 _dispatch_<source_type> 注册点即可。

分发渠道:Bark / 飞书 / 企业微信 / Slack / PushDeer / 通用 Webhook 六类实例

Bluebird 内置 6 类渠道:

渠道实例字段卡片能力
Barkdevice keyiOS 推送
飞书App ID/Secret + receive_id彩色卡片(按事件类型配色)
企业微信webhook URL文本/Markdown
SlackWebhook URL + 可选签名密钥Block Kit(同套配色)
PushDeerpush keyiOS 推送
通用 WebhookURL + 签名密钥任意 HTTP 接收端

渠道实例化之后,改接收人 = 编辑渠道 = 改一处——换群、换频道、加新渠道都面板操作,零改脚本。单渠道失败不影响其他渠道到达,失败进审计面板可追溯。


4. 集中编排与查看

通知源详情:勾选分发渠道

信息源和分发渠道的关系是在面板里勾的,不是写死的——一条通知并行推到多个渠道。临时静音、换接收群、加新渠道,改完即生效;整源静音关掉来源行开关就行。

概览:推送统计与趋势

历史:按来源/渠道筛选的审计面板

所有推送进审计面板,按来源 / 渠道 / 成败筛选;趋势图按日折线,三视角切换。配置与查看都在同一面板,"集中管理"才算闭环。


5. 几个有意思的设计取舍

  1. stdlib 单文件、零依赖:部署成本优先。跑 NAS / 树莓派 / 临时 VPS 一行命令起,不强制 Docker。

  2. 单渠道失败不影响其他:不是重试(解决不了"目标服务真挂了"),是隔离——一个渠道挂掉不该影响告警的可达性。

  3. 配置进 DB、每次请求读最新:"改完即生效"的承诺,避免缓存失效复杂度。代价是每次请求多一次 DB 读,单文件自托管规模够用。

  4. 渠道实例化允许重名、不强制 ID 唯一:渠道名只作展示名和分组名,不进 URL。允许中文、emoji、≤32 字符;ID 是后端生成的稳定标识,对用户透明。


6. 方案对比:为什么没选它们

方案形态信息源集中分发集中即改即生效部署门槛适合规模
自建散落脚本代码❌❌ key 硬编码—无1-3 个项目
IM 后台 webhookSaaS❌⚠️ 单渠道多端⚠️ 进后台改无单渠道多接收人
Server 酱 / PushPlus / 方糖SaaS⚠️ 模板化⚠️ 单一端✅无个人轻量通知
ApprisePython 库⚠️ 自封装✅ 几十渠道⚠️ 自己写 web 层中开发者自己集成
Gotify自托管服务❌ 偏 push 端⚠️ 渠道少✅低安卓端集中收通知
Bluebird自托管单文件✅ 二段抽象✅ 6 渠道✅⭐个人/小团队多项目

为什么没选 Apprise:好库,但库形态——要自己写 web 层、UI、DB、缓存失效,做完等于自己发明 Bluebird。

为什么没继续用 Server 酱系:多渠道并行 × 多接收人分组 × 推送审计,不在它的设计目标里;付费后仍是单一接收端。

为什么不做 IM 交互机器人:Bluebird 只做单向 webhook 出站,slash command / 按钮 / OAuth 是另一段位复杂度,目前用不上。


7. 适用边界

不是所有人都需要 Bluebird:

  • 只有 1 个项目要接推送 → 直接配 IM 后台 webhook 就够;
  • 要完整交互(slash command / 按钮 / OAuth)→ 用原厂机器人;
  • 要 RBAC / SSO / 审计合规 → 买企业级 SaaS;
  • 要 100+ SaaS 集成 → 别指望。

目标用户很窄:自托管玩家,手里一堆项目和脚本要接通知,曾经被散落的 webhook 配置折磨过。


8. 最后

我做 Bluebird 的取舍就四个字——免费、轻量、自托管、可定制。stdlib 单文件跑 NAS / VPS / 树莓派都一行命令起;想要新适配层、新渠道、新事件类型,fork 一下加 _dispatch_<source_type> 即可。

最重要——我自己就是它的第一个用户。日常 GitHub 通知、Kimi 任务结束、自建监控告警全在用,至今没找到更合适的替代。

issue 和 PR 都欢迎。下一类适配(GitLab / Sentry / Grafana)想在仓库里讨论优先级。