利用微信打造各类监控消息推送

原文地址 saucer-man.com

1. 背景

在日常的工作生活中,经常用到长期后台运行的程序,比如子域名监控,github 监控,各种论坛签到,网站动态监控等等,这些都可以归结为属于定时任务,每天跑一次或者每小时跑一次,这种程序有个痛点就是状态监测,比如今天论坛签到成功了吗?今天 github 发现新的漏洞了吗?

这类问题需要一个统一的消息推送解决方案,比如微信、钉钉、邮件、telegram 等等,但是都有各自的缺点:

  • 微信:不带推送 api 功能
  • 钉钉:需要多安装一个 app
  • 邮件:不够简单快捷,邮件太多容易泛滥
  • telegram:需要手机长期挂代理

之前一直在用 server 酱,利用公众号的通道推送消息,但因微信曾发布下线公告,所以已经不被推荐使用。

然后转向 server 酱的企业微信应用消息通道,发现其免费用户一天推送额度只有 5 条,且只显示标题,又想白嫖又想爽那是不行的,于是尝试站着把消息推送了。

2. 利用企业微信发送消息

企业微信本身可以发送添加群机器人,发送消息,也可以利用企业微信的应用发送消息。具体的文档可以见:https://work.weixin.qq.com/api/doc/90000/90135/90664

这里我的需求有三个:

  1. 只用微信即可接收消息,不需要独立安装企业微信
  2. 发送消息无次数限制
  3. 可以直接看到消息的全部内容

于是选用了发送应用消息的 api:https://work.weixin.qq.com/api/doc/90000/90135/90236

方法很简单:

  1. 先认证获取 access_token
  2. 然后发送具体消息即可,支持图文、文字、语言,视频等

但是我在每个需要监控的应用里都写一套这样的逻辑,那不是很麻烦?

于是想到可以模仿 server 酱,提供一个 webhook 的 api,只需要一条 http 请求即可发送消息。具体的逻辑就是封装了上面的两步,然后提供了对外的 api 功能。项目主页:https://github.com/saucer-man/wepush

下面说一下部署的流程:

2.1 创建企业和企业微信应用

详细的步骤可以参考:https://sct.ftqq.com/forward

  1. 创建企业,200 人以下免认证
  2. 创建企业应用,名为消息推送,图标自己网上找一个即可
  3. 利用微信插件关注微信,可以直接在微信中可以收发企业微信的消息

2.2 部署 server

git clone https://github.com/saucer-man/wepush
cd wepush
vim wepush.env  
docker-compose build && docker-compose up -d

其中主要需要填写的有:

  • AuthToken 此 api 接口的认证 token, 随便填写一串字符串即可
  • CorpSecret 企业应用 secret
  • CorpId 企业 ID
  • AgentId 企业应用 ID
  • LogLevel 日志详细级别 (可以选 debug/info/warn)

默认端口为8001,日志目录为./log,可以从docker-compose.yml中修改

2.3 使用教程

本着大道至简,九九归一的原则,api 调用只支持 POST json 请求。

  • curl 版本
curl http://localhost:8001/wepush -H "Content-Type:application/json" -H "token:xxxxx" -X POST -d '{"type": "text","touser": "@all","msg": "hello\nworld"}'
  • python 版本
import requests
data = {"type": "text","touser": "@all","msg": "hello\\nworld"}
response = requests.post('http://localhost:8001/wepush?token=xxxxx', json=data)
  • golang 版本
package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "strings"
)

func main() {
    client := &http.Client{}
    var data = strings.NewReader(`{"type": "text","touser": "@all","msg": "hello\nworld"}`)
    req, err := http.NewRequest("POST", "http://localhost:8001/wepush", data)
    if err != nil {
        log.Fatal(err)
    }
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("token", "123")
    resp, err := client.Do(req)
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()
    bodyText, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%s\n", bodyText)
}

参数解释:

  • token:此 api 接口认证 token,可以放在 header 中,也可以放在 url 的 query 中
  • type:发送的消息类型,支持 text 和 markdown(不填的话默认为 markdown)
  • touser:成员 ID 列表,即消息接收者,多个接收者用‘|’分隔,最多支持 1000 个。(不填的话默认为 @all)
  • msg:需要发送的消息内容

效果为:

看起来非常 nice