基于NodeJS实现企业微信机器人推送

Posted crper

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于NodeJS实现企业微信机器人推送相关的知识,希望对你有一定的参考价值。

前言

公司是企业微信协同的,刚好之前搞得CLI有输出报告文件的功能;
想了想也可以打通这个流程,让沟通成本降低【不用人工转发】;

运转流程:生成报告-> 推送文件 -> 企业微信群。
再把这个流程接入到自动化执行的流程,就更加人性化了~

那么,这里说说如何利用node快速覆盖这个场景!

需求及环境

前置知识储备

  • IO操作及文件流的概念
  • 加密解密的基础

没玩过的也能跟着帖子,逐步查阅相关资料长见识~

功能需求

  • 配置一个企业微信机器人key即可使用
    • 考虑CI环境可以运行,部分配置支持从环境变量接收
  • 支持推送图片
  • 支持推送文本,Markdown
  • 支持推送文件【比如json,excel等】

环境依赖

成品图


代码实现

webhook初始化配置

/**
 *
 * @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`,
  ;
;

文本推送

/**
 *
 * @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#%E6%96%87%E6%9C%AC%E7%B1%BB%E5%9E%8B | 企业微信机器人配置
 * @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的语法支持力度并不高,只有非常基础的几个写法

/**
 *
 * @param string mdTpl markdown的字符串模板,仅生效特定子集
 * @see @link https://developer.work.weixin.qq.com/document/path/91770#markdown%E7%B1%BB%E5%9E%8B | 企业微信机器人配置
 * @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实现,都不用装其他库了。

/**
 *
 * @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

上传文件到企业微信

/**
 * 上传文件到企业微信
 * @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;
  );


推送文件到机器人

/**
 * 发送文件到企业微信群
 * @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来写的,还能写成链式调用的,见仁见智了哈;
企业微信机器人还支持图文这些,若是图片是外链可以考虑这种公众号风格的排版。
有不对之处请留言,谢谢阅读~

以上是关于基于NodeJS实现企业微信机器人推送的主要内容,如果未能解决你的问题,请参考以下文章

基于NodeJS实现企业微信机器人推送

nodeJS实现企业微信机器人每天定时发消息实例 定时任务

python:消息推送 - 企业微信机器人推送

PowerShell 实现企业微信机器人推送消息

物联网服务NodeJs-5天学习第三天实战篇① ——10行代码给她造个熬夜提醒睡觉机器人

Python借助企业微信群机器人推送消息和文件