通过企业微信发送消息通知有两种方式: 两者的对比 适用范围 群机器人,顾名思义,是只能在群组中才能添加的机器人。二人对话的聊天框中是无法添加的,但我们可以通过一些技巧来实现。 有时候我们想单独测试下我们的机器人,又不想打扰别人,可以用如下的方式操作。 先默默拉几个人建一个群,注意,不要发送消息、不要改群名。不要进行任何操作。然后再默默把其他人踢掉,就可以形成二人群或者一人群了。其他人是完全不感知的,他们是不知道自己被拉群了,然后又被踢掉了。 比如这个群,这群里只有我一个人: 群里任何人都可以添加机器人。 添加成功后,就会有一个对应的 webhook 地址,其他应用使用这个地址,就可以通过群机器人发送消息了。 群机器人发送消息还是比较简单的,按照文档配置即可。开发者可以按以下说明向这个地址发起 HTTP POST 请求,即可实现给该群组发送消息。 官方发送不同格式消息的地址:https://developer.work.weixin.qq.com/document/path/91770 如在 shell 脚本中: 比如我在流水线是用的群机器人,来提示我流水线的启动和结束。gitlab 流水线可以执行 shell 脚本,我们直接编写 shell 脚本即可。 很奇怪,这段代码在博客里一直发布不成功,就改成截图了。 有的同学会通过后台服务发送一些信息,如在 nodejs 中: 若您觉得您的群机器人功能很不错,后台服务也比较稳定,有的同学会搞一些笑话机器人、每周信息汇总机器人、每日一语机器人等等。就可以将其发布到公司范围内,其他人可以就把他添加到别的群组里。 添加机器人时,可以从这里选择已发布到公司的机器人。 对于没有发布到公司的群机器人,只能靠大家的口口相传了。 企业微信机器人引入简单,使用方便。相应的,能力也有很大的局限性,比如无法鉴权,谁拿到这个地址,都能发送消息;同时,只有在有这个机器人的群里,才能收到消息,否则就无法感知。 比如上面的那个群里,群里只有我自己,我就可以接收到通知,但其他人,虽然他们触发流水产生的群机器人消息,但因为他们不在这个群里,就无法收到通知。 这需要拥有该企业微信的管理员权限,才能创建自建应用。 一. 进入管理后台,选择应用管理,下拉到底部,点击创建应用; 二. 填入提前准备好的 logo 图片(建议使用 750*750,1M 以内的 jpg、png 图片)、应用名称和应用介绍(选填),然后选择可见范围; 同时,还要准备好域名和几个 IP,这里需要从管理后台下载一个验证文件,放到该域名对应的服务器根目录中,域名验证通过后就可以添加 IP 白名单了。 三. 创建成功;得到如下的几条数据(获取方式:https://developer.work.weixin.qq.com/document/path/90665): 若您不是管理员,还请将第 2 序列中准备好的数据给到公司的管理员,待管理员创建成功后,得到第 3 序列中需要的数据。 自建应用的特点: 企业自建应用的任何功能,都要首先获取到 access_token。 官网地址:https://developer.work.weixin.qq.com/document/path/91039。 通过已获取到的 corpId 和 secret 就可以拿到 access_token 了。不过 token 接口有请求频率的限制,并且获取到的 token 有 7200s(2 小时)的有效期,程序需要缓存该 token。 企业自建应用,除消息推送外,还有很多其他的功能,如通讯录管理、身份验证、消息推送、创建群聊等,不过我们这里主讲消息推送这块。 跟群机器人类似,消息也有很多种类型,每种类型的消息所需要的字段也不一样,大家可自行查阅文档。这里仅举一个发送文本消息的例子: 我们在创建好「消息提醒」的自建应用后,其他的内网服务(如禅道、知识库、流水线、错误率警告等服务),都可以通过该应用向用户或部门发送通知,方便周知各种内容的变更。 自建应用还有一个很重要的功能,就是可以接收每个用户发送过来的任何消息(包括底部菜单的点击),然后再针对该消息,进行相应的回复。 这里的配置相对来说比较麻烦一些: 在接收消息之前,首先要在管理后台配置接收消息的线上地址,在保存地址时,就会校验这个地址的有效性,即企业微信会以 GET 请求的方式,携带一些参数,请求该 url,若能正常解密 url 参数中的内容并返回,即为配置成功。 在接收并回复消息模块中,有三个过程: 第 2、3 过程是连续的,若要回复消息,则直接返回即可;若不想回复消息或回复需要很长的时间(官方会等待 5 秒时间),可以直接在第 2 步中返回 200(即以空串为返回包),然后再通过上面的“发送消息推送”,主动给相关用户推送消息。 各种加密解密算法也挺绕的,官方也出了一些相关语言的包(库),可以直接拿来使用(https://developer.work.weixin.qq.com/document/path/90307)。我这里只有一个能运行 php 的主机,因此选择了 php 语言的库。各位可以根据自己的需要,选择相应的库即可。 我这里使用了 codeigniter 框架。 接收消息这里很特殊,企业微信发送过来的是一个 xml string 类型的。我也是好久没写过 php 了,不知道怎么接收这个数据,用 post 方式尝试了 N 多次,也没成功。后来才查到相关资料是用 接收到所有的数据,再通过官方提供的解密函数,解析出真实的 xml 信息。注意,这里并不是单纯的消息,还有各种如发送用户、发送的消息类型、发送的时间等信息。还得需要通过 xml 的进一步解析,才能解析出各个字段的值。 回复消息与接收消息差不多,根据官方要求的字段格式,拼接 xml,然后再以 string 类型进行加密。 比如一些活动报名、或者中奖名单等,有一长串的用户名单,需要拉群知会一些消息。若要手动创建的话,那每次都得搜索拉入,需要很长时间。但若通过接口创建的话,几秒钟就可以。 创建群聊官方地址:https://developer.work.weixin.qq.com/document/path/90245。 设置好群聊名称、群主、群成员、群 Id(可选),就可以创建了。创建成功后,会返回该群聊的 id: 群聊创建成功后,会返回该群聊的 id,用于后续的比如修改群聊标题、群聊成员、发送群聊消息等操作。而且,群聊刚创建成功时,是不会立即在聊天框中展示出来的,需要通过发送消息,来激活该群聊。 这里也有一个发送消息的接口,但这里的接口跟上面的“发送消息推送”不是同一个接口。而且,这里的接口还需要指定群 id(即 chatid)才能发送消息。 这里发送消息的格式,也是有多种格式。 群机器人和企业自建应用有着不同的接入难度和接入场景,各位可以根据自己的需要,来选择适合自己的方式。
接入难易程度
发送范围
是否可以接收回调
群机器人
简单,任何人都可以创建,并添加到群组中(默认任何人,但管理员可以开启白名单)
只能往群组中发送消息
不能,只能发送,不能接收
企业自建应用
需要管理员添加,并需要配置发送消息服务器的 IP 白名单
可以指定给某人或某几人或某部门发送消息(在管理员指定范围内)
可以接收消息,实现互动
群机器人 #
如何创建小群测试 #
添加群机器人 #
注意,不要泄露您的 webhook 地址,避免他人通过该地址发送垃圾消息。如何发送消息 #
curl 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxxx-yyyyyy-zzzzzz' \
-H 'Content-Type: application/json' \
-d '
{
"msgtype": "text",
"text": {
"content": "hello world"
}
}'
const axios = require("axios");
const send = async () => {
const result = await axios({
url: "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxxx-yyyyyy-zzzzzz",
method: "post",
data: {
msgtype: "news",
news: {
articles: [
{
title: "中秋节礼品领取",
description: "今年中秋节公司有豪礼相送",
url: "www.qq.com",
picurl:
"http://res.mail.qq.com/node/ww/wwopenmng/images/independent/doc/test_pic_msg1.png",
},
],
},
},
});
if (result.status === 200 && result.data?.errcode === 0) {
console.log("success", result.data);
} else {
console.error("fail");
}
};
send();
把机器人发布到公司 #
点评 #
企业自建应用 #
如何创建企业自建应用 #
获取 access_token #
const axios = require("axios");
const { corpId, secret } = require("./utils/secret");
const cache = require("./utils/cache");
const getAccessToken = async () => {
const cacheToken = await cache.get("token");
if (cacheToken) {
return cacheToken;
}
const { status, data } = await axios({
url: "https://qyapi.weixin.qq.com/cgi-bin/gettoken",
params: {
corpid: corpId,
corpsecret: secret,
},
});
if (status === 200 && data.errcode === 0) {
cache.set("token", data.access_token);
return data.access_token;
}
return null;
};
module.exports = getAccessToken;
发送消息推送 #
const axios = require("axios");
const getAccessToken = require("./src/get-access-token");
const { agentId } = require("./src/utils/secret");
const sendTextMsg = async () => {
const accessToken = await getAccessToken();
const { status, data } = await axios({
url: `https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=${accessToken}`,
method: "post",
data: {
touser: "xiaowenzi", // 多个用户,用 | 隔开
// toparty: 'PartyID1|PartyID2', // 部门 id
// totag: 'TagID1 | TagID2',
msgtype: "text",
agentid: agentId,
text: {
content:
'你的快递已到,请携带工卡前往邮件中心领取。\n 出发前可查看邮件中心视频实况,聪明避开排队。',
},
},
});
console.log(status, data);
};
接收并回复消息 #
加密和解密的算法与官方已有库 #
验证 url #
// 检测 url 的合法性
private function checkValidUrl(){
$this->load->library('WXBizMsgCrypt');
$this->wxbizmsgcrypt->init($this->token, $this->encodingAesKey, $this->corpId);
$sVerifyMsgSig = $this->input->get("msg_signature");
$sVerifyTimeStamp = $this->input->get("timestamp");
$sVerifyNonce = $this->input->get("nonce");
$sVerifyEchoStr = $this->input->get("echostr");
// 需要返回的明文
$sEchoStr = "";
$errCode = $this->wxbizmsgcrypt->VerifyURL($sVerifyMsgSig, $sVerifyTimeStamp, $sVerifyNonce, $sVerifyEchoStr, $sEchoStr);
if ($errCode == 0) {
echo $sEchoStr;
} else {
print("ERR: " . $errCode . "\n\n");
}
}
接收消息 #
file_get_contents("php://input")
的方式来接收。/**
* 接收消息
* 参数接收一些加密参数,具体消息是通过post的body传过来的,
* 在php中,若body是一个纯字符串,需要用 file_get_contents('php://input') 的方式来接收
*
* 关于file_get_contents和post的区别:
* @see https://www.cnblogs.com/phpper/p/9574419.html
*/
private function decodeMsg(){
$this->load->library('WXBizMsgCrypt');
$this->wxbizmsgcrypt->init($this->token, $this->encodingAesKey, $this->corpId);
$sReqMsgSig = $this->input->get("msg_signature");
$sReqTimeStamp = $this->input->get("timestamp");
$sReqNonce = $this->input->get("nonce");
// post请求的密文数据
$sReqData = file_get_contents('php://input');
$sMsg = ""; // 解析之后的明文
$errCode = $this->wxbizmsgcrypt->DecryptMsg($sReqMsgSig, $sReqTimeStamp, $sReqNonce, $sReqData, $sMsg);
if ($errCode == 0) {
// 解密成功,sMsg即为xml格式的明文
echo ($sMsg);
return $sMsg;
// TODO: 对明文的处理
/*
"
*/
} else {
print("ERR: " . $errCode . "\n\n");
}
}
回复消息 #
private function sendMsg(){
$this->load->library('WXBizMsgCrypt');
$this->wxbizmsgcrypt->init($this->token, $this->encodingAesKey, $this->corpId);
// 接收消息
$getMsg = $this->decodeMsg();
// 接收到消息后,经过处理,然后需要返回给用户消息了
$now = time();
// 需要发送的明文
$sRespData = "
在群聊会话中发通知 #
创建群聊 #
{
"name": "NAME",
"owner": "userid1",
"userlist": ["userid1", "userid2", "userid3"],
"chatid": "CHATID"
}
// 创建群聊
const createGroupChat = async () => {
const accessToken = await getAccessToken();
const { status, data } = await axios({
url: `https://qyapi.weixin.qq.com/cgi-bin/appchat/create?access_token=${accessToken}`,
method: "post",
data: {
// chatid: Date.now(),
name: `企业内建应用创建的群聊-${Date.now().toString(36)}`,
owner: "xiaowenzi",
userlist: ["xiaowenzi", "dawenzi"], // 成员名单至少需要2个人
},
});
// 创建成功后,不会立即在聊天框中展示出来,需要通过发送消息,来激活该群聊
console.log("createGroupChat", status, data); // chatid: wruVG5OwAAQF_MwwspiyXmD8T7NQt8yA
};
向群聊中发送消息 #
const sendMsgToGroup = async () => {
const accessToken = await getAccessToken();
const { status, data } = await axios({
url: `https://qyapi.weixin.qq.com/cgi-bin/appchat/send?access_token=${accessToken}`,
method: "post",
data: {
chatid: "chatid", // 修改自己的群聊id
msgtype: "markdown",
markdown: {
content:
'# 你的快递已到\n请携带工卡前往邮件中心领取\n邮件中心视频实况,聪明避开排队',
},
safe: 0,
},
});
console.log("sendMsgToGroup", status, data);
};
总结 #
版权属于:
加速器之家
作品采用:
《
署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)
》许可协议授权
评论