给 notify-user 技能加上微信推送:移植 Server酱 与 PushPlus 的实战记录
背景
我维护一个开源的桌面代理通知技能 notify-user,用途很简单:让 AI 干完活之后自动给用户发一条"完事了"的消息。之前已经支持 Telegram 机器人、SMTP 邮箱、Resend API 三类渠道,但有个现实问题——Telegram 在国内网络环境基本不可用,邮件又容易被折叠。最顺手的送达终端其实是微信。
这次从我自己一个跑了很久的签到脚本(GLaDOS_Checkin)里,把两条经过实战验证的微信推送渠道移植进了技能:Server酱和PushPlus。过程不复杂,但有几个坑值得记下来。
为什么是这两家
两者原理相同:你用微信扫码登录他们的平台,拿到一个 Key/Token,之后向固定端点 POST 一条消息,消息就通过微信服务号/公众号推到你手机上。优点非常明显:
- 不需要域名、不需要服务器、不需要备案
- 免费额度对个人提醒场景完全够用
- 送达终端是微信本身,比邮件及时得多
Server酱接入要点
在 sct.ftqq.com 微信扫码登录后,SendKey 页面复制一串 SCTxxxx 形式的密钥,然后发一个表单 POST:
POST https://sctapi.ftqq.com/{SENDKEY}.send
Content-Type: application/x-www-form-urlencoded
title=构建完成&desp=任务已跑完,耗时 3 分钟
响应是 JSON,成功判定是业务码 code == "0",不是 HTTP 200。免费额度每天 5 条,超了会返回配额错误码,脚本里要单独识别。
PushPlus 接入要点
pushplus.plus 同样微信扫码拿 token,走 JSON POST:
POST https://www.pushplus.plus/send
Content-Type: application/json
{"token": "xxx", "title": "构建完成", "content": "任务已跑完", "template": "txt"}
成功判定是 code == 200。返回里带 trace_id,排查问题时有用。
踩坑记录
1. HTTP 200 不代表发送成功。两个平台都是"HTTP 层永远 200,成败看响应体业务码"的设计。早期版本的签到脚本就栽在这里——只检查状态码,消息实际没发出去也显示成功。所以移植时统一封装了判断:_send_json / _send_form 返回响应体,由各渠道自己的规则判定成败。
2. 密钥会出现在 URL 里。Server酱的 SendKey 是路径参数,一旦把请求 URL 打进日志就泄露了。所以发信函数的错误路径全部只输出"渠道名 + HTTP 状态 + 打码后的响应体",URL 永远不落盘。技能里还有一道 SECRET_KEY_RE 正则,凡变量名命中 TOKEN/SECRET/KEY/SENDKEY 等模式的值,一律先打码再进输出。
3. 用户没关注服务号 = 静默失败。首次使用必须先扫码关注对应的微信服务号(Server酱 或 "pushplus 推送加"),否则消息发出去了、接口也返回成功,但微信里永远收不到。这一条我直接写进了技能的排障文档。
4. 代理环境变量不要静默继承。系统里若有 http_proxy,Python 的 urllib 会悄悄走它,出问题时很难定位卡在哪一跳。脚本默认忽略环境代理,只在显式设置 NOTIFY_PROXY 时才走——故障面小很多。
设计:自动降级链
技能最终支持六种送达方式,默认按可靠性排序自动降级:
AUTO_ORDER_DEFAULT = ("telegram", "smtp", "resend", "serverchan", "pushplus")
排前面的渠道密钥不存在或发送失败时自动落到下一个,全部失败才退出非零并附人工排查指引。微信渠道排在邮件之后,作为"没配邮箱/Telegram 时开箱即用"的兜底——毕竟它的配置成本是全渠道里最低的:扫个码、贴个 Key 就完事。
小结
移植本身只花了一个多小时,大部分时间花在把"实战里踩过的坑"固化成判定逻辑:业务码而非 HTTP 状态码、密钥打码、服务号关注检查、代理不静默继承。这四条对任何做消息推送集成的项目都适用。
技能已开源,欢迎交流:github.com/ink358/notify-user
- 点赞
- 收藏
- 关注作者
评论(0)