前言
公司是企业微信协同的,刚好之前搞得CLI有输出报告文件的功能; 想了想也可以打通这个流程,让沟通成本降低【不用人工转发】;
运转流程:生成报告-> 推送文件 -> 企业微信群。 再把这个流程接入到自动化执行的流程,就更加人性化了~
那么,这里说说如何利用node快速覆盖这个场景!
需求及环境
前置知识储备
- IO操作及文件流的概念
- 加密解密的基础
没玩过的也能跟着帖子,逐步查阅相关资料长见识~
功能需求
- 配置一个企业微信机器人key即可使用
- 考虑CI环境可以运行,部分配置支持从环境变量接收
- 支持推送图片
- 支持推送文本,Markdown
- 支持推送文件【比如json,excel等】
环境依赖
- Node 16
- npm deps [core: Node原生模块]
- axios
- form-data
- core
- crypto
- path
- fs
- 企业微信开发者中心-群机器人
- https://developer.work.weixin.qq.com/document/path/91770成品图
代码实现
webhook初始化配置
代码语言:javascript复制/**
*
* @param {*} key 企业微信机器人推送的key
* @returns 配置信息
*/
const getConfig = (key) => {
const hookKey = key || process.env?.WECHAT_WEBHOOK_KEY || 'xxxxxxxx';
if (typeof hookKey !== 'string' && !hookKey) throw new Error(`${hookKey} must be string , no empty`);
return {
key: hookKey,
url: `https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=${hookKey}`,
uploadURL: `https://qyapi.weixin.qq.com/cgi-bin/webhook/upload_media?key=${hookKey}&type=file`,
};
};
文本推送
代码语言:javascript复制/**
*
* @param { string } text 普通文本的内容
* @param {*} options
* @param {string[]} options.mentioned_list userid的列表,提醒群中的指定成员(@某个成员),@all表示提醒所有人,如果开发者获取不到userid,可以使用mentioned_mobile_list
* @param {string[]} options.mentioned_mobile_list 手机号列表,提醒手机号对应的群成员(@某个成员),@all表示提醒所有人
* @see {@link https://developer.work.weixin.qq.com/document/path/91770#文本类型 | 企业微信机器人配置}
* @returns
*/
function sendTextToEnterpriseWeChatGroup(text = '', options = {}) {
const url = getConfig().url;
const data = {
msgtype: 'text',
text: {
content: text,
mentioned_mobile_list: ['@all'],
...options,
},
};
return axios({
url,
method: 'post',
headers: {
'Content-Type': 'application/json',
},
data,
});
}
Markdown推送
markdown的语法支持力度并不高,只有非常基础的几个写法
代码语言:javascript复制/**
*
* @param {string} mdTpl markdown的字符串模板,仅生效特定子集
* @see {@link https://developer.work.weixin.qq.com/document/path/91770#markdown类型 | 企业微信机器人配置}
* @returns
*/
function sendMarkdownTextToEnterpriseWeChatGroup(mdTpl = '') {
const url = getConfig().url;
const data = {
msgtype: 'markdown',
markdown: {
content: mdTpl,
},
};
return axios({
url,
method: 'post',
headers: {
'Content-Type': 'application/json',
},
data,
});
}
图片推送
图片源文件推送的使用场景挺多的,比如测评报告【图片】,比如数据概览图,亦或者辅助排版的美化; 图片的推送需要特殊点,有两个强制要求!
- 源文件算出md5
- 图片流转成base64
不过这两个可以node的核心API实现,都不用装其他库了。
代码语言:javascript复制/**
*
* @param {*} filename 文件路径
* @returns
*/
function sendImgToEnterpriseWeChatGroup(filename) {
if (typeof filename === 'string' && !fs.existsSync(filename)) throw new Error(`${filename} no exist`);
const url = getConfig().url;
const file = filename ?? path.join(__dirname, './performance-banner.png');
const buffer = fs.readFileSync(file);
const base64data = buffer.toString('base64');
// 获取该版本node模块的算法签名列表和hash算法列表
// console.log(crypto.getCiphers());
// console.log(crypto.getHashes());
// https://nodejs.org/api/crypto.html#cryptocreatehashalgorithm-options
const md5 = crypto.createHash('md5').update(buffer).digest('hex');
const data = {
msgtype: 'image',
image: {
base64: base64data,
md5,
},
};
return axios({
url,
method: 'post',
headers: {
'Content-Type': 'application/json',
},
data,
});
}
tips: 这里有一个要注意点是我给了一张默认图,复制记得同步调整哦!
文件推送
文件推送需要分两步,先上传文件,获取响应带回来的媒体id。再把这个作为推送接口的参数。
值得注意的是,最好使用multipart/form-data
,好处就是兼容性强,且拿到文件名这些。
我用过另外一个模式,推送到群发送是不可阅读的文件,如图:
接着往下走,那么我们如何合理高效的上传文件呢? 因为我用了axios, 官方有一个node的标准案例,拿来即用; https://github.com/axios/axios#formdata
上传文件到企业微信
代码语言:javascript复制/**
* 上传文件到企业微信
* @param {string} filename 上传的文件
* @return Promise<response>
*
* response:
* ```
* {
* errcode: 0,
* errmsg: 'ok',
* type: 'file',
* media_id: '3-txPJzsW5L5IMXDcQjlcp5OxUenF_YB_ib8zRJwE4AgEVb97RbjG-PtF-pjP42jk',
* created_at: '1662452066'
* }
* ```https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=
*/
function uploadFileToEnterpriseWeChat(filename) {
const url = getConfig().uploadURL;
const readStream = fs.createReadStream(filename);
// 上传文件使用FormData
// nodejs里使用FormData:https://github.com/form-data/form-data
const formData = new FormData();
formData.append('media', readStream);
return axios.post(url, formData).then((res) => {
return res.status === 200 && res.data;
});
}
推送文件到机器人
代码语言:javascript复制/**
* 发送文件到企业微信群
* @param {string} media_id 通过上传接口获取的`media_id`
*/
function sendFileToEnterpriseWeChatGroup(media_id) {
const url = getConfig().url;
const data = {
msgtype: 'file',
file: {
media_id,
},
};
return axios({
url,
method: 'post',
headers: {
'Content-Type': 'application/json',
},
data,
});
}
总结
至此一个简易的封装就实现了,若换class
来写的,还能写成链式调用的,见仁见智了哈;
企业微信机器人还支持图文这些,若是图片是外链可以考虑这种公众号风格的排版。
有不对之处请留言,谢谢阅读~