收藏系列-告警接入钉钉

王猴卖瓜

共 5319字,需浏览 11分钟

 · 2021-04-27

场景介绍

企业内部有较多系统支撑着公司的核心业务流程,譬如CRM系统、交易系统、监控报警系统等等。通过钉钉的自定义机器人,可以将这些系统事件同步到钉钉的聊天群。


说明 

当前机器人尚不支持应答机制,该机制指的是群里成员在聊天@机器人的时候,钉钉回调指定的服务地址,即Outgoing机器人。


步骤一:获取自定义机器人Webhook

  1. 打开机器人管理页面。以PC端为例,打开PC端钉钉,点击头像,选择机器人管理

  2. 在机器人管理页面选择自定义机器人,输入机器人名字并选择要发送消息的群,同时可以为机器人设置机器人头像。

  3. 完成必要的安全设置,勾选我已阅读并同意《自定义机器人服务及免责条款》,然后单击完成

    目前有3种安全设置方式,请根据需要选择一种:

    • 自定义关键词:最多可以设置10个关键词,消息中至少包含其中1个关键词才可以发送成功。

      例如添加了一个自定义关键词:监控报警,则这个机器人所发送的消息,必须包含监控报警这个词,才能发送成功。

    • 加签

    • IP地址(段):设定后,只有来自IP地址范围内的请求才会被正常处理。支持两种设置方式:IP地址和IP地址段,暂不支持IPv6地址白名单,格式如下。

      格式 

      说明

      1.1.1.1

      开发者的出口公网IP地址(非局域网地址)

      1.1.1.0/24

      用CIDR表示的一个网段

    1. timestamp+"\n"+密钥当做签名字符串,使用HmacSHA256算法计算签名,然后进行Base64 encode,最后再把签名参数再进行urlEncode,得到最终的签名(需要使用UTF-8字符集)。

      参数

      说明

      timestamp

      当前时间戳,单位是毫秒,与请求调用时间误差不能超过1小时。

      secret

      密钥,机器人安全设置页面,加签一栏下面显示的SEC开头的字符串。

      签名计算示例代码(Java)

      import javax.crypto.Mac;
      import javax.crypto.spec.SecretKeySpec;
      import org.apache.commons.codec.binary.Base64;
      import java.net.URLEncoder;

      public class Test {
      public static void main(String[] args) throws Exception {
      Long timestamp = System.currentTimeMillis();
      String secret = "this is secret";

      String stringToSign = timestamp + "\n" + secret;
      Mac mac = Mac.getInstance("HmacSHA256");
      mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
      byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));
      String sign = URLEncoder.encode(new String(Base64.encodeBase64(signData)),"UTF-8");
      System.out.println(sign);
      }

      }

      复制成功

      签名计算代码示例(Python)

      #python 3.8 
      import time
      import hmac
      import hashlib
      import base64
      import urllib.parse

      timestamp = str(round(time.time() * 1000))
      secret = 'this is secret'
      secret_enc = secret.encode('utf-8')
      string_to_sign = '{}\n{}'.format(timestamp, secret)
      string_to_sign_enc = string_to_sign.encode('utf-8')
      hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
      sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))
      print(timestamp)
      print(sign)

      复制成功

    2. 把 timestamp和第一步得到的签名值拼接到URL中。

      https://oapi.dingtalk.com/robot/send?access_token=XXXXXX&timestamp=XXX&sign=XXX

      复制成功

      参数

      说明

      timestamp

      第一步使用到的时间戳。

      sign

      第一步得到的签名值。

  4. 完成安全设置后,复制出机器人的Webhook地址,可用于向这个群发送消息,格式如下:

    https://oapi.dingtalk.com/robot/send?access_token=XXXXXX

    复制成功


    注意 

    请保管好此Webhook 地址,不要公布在外部网站上,泄露后有安全风险。

步骤二:使用自定义机器人

获取到Webhook地址后,用户可以向这个地址发起HTTP POST 请求,即可实现给该钉钉群发送消息。


注意 


  • 发起POST请求时,必须将字符集编码设置成UTF-8。

  • 每个机器人每分钟最多发送20条。消息发送太频繁会严重影响群成员的使用体验,大量发消息的场景 (譬如系统监控报警) 可以将这些信息进行整合,通过markdown消息以摘要的形式发送到群里。

当前自定义机器人支持文本 (text)、链接 (link)、markdown(markdown)、ActionCard、FeedCard消息类型,请根据自己的使用场景选择合适的消息类型,达到最好的展示样式。详情参考:消息类型及数据格式。

自定义机器人发送消息时,可以通过手机号码指定“被@人列表”。在“被@人列表”里面的人员收到该消息时,会有@消息提醒。免打扰会话仍然通知提醒,首屏出现“有人@你”。

步骤三:测试自定义机器人

通过以下方法,可以快速验证自定义机器人是否可以正常工作:

使用命令行工具curl。


说明 

为避免出错,将以下命令逐行复制到命令行,需要将xxxxxxxx替换为真实access_token;若测试出错,请检查复制的命令是否和测试命令一致,多特殊字符会报错。

curl 'https://oapi.dingtalk.com/robot/send?access_token=xxxxxxxx' \
-H 'Content-Type: application/json' \
-d '{"msgtype": "text","text": {"content": "我就是我, 是不一样的烟火"}}'

复制成功

SDK请求示例(Java)

DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/robot/send?access_token=566cc69da782ec******");
OapiRobotSendRequest request = new OapiRobotSendRequest();
request.setMsgtype("text");
OapiRobotSendRequest.Text text = new OapiRobotSendRequest.Text();
text.setContent("测试文本消息");
request.setText(text);
OapiRobotSendRequest.At at = new OapiRobotSendRequest.At();
at.setAtMobiles(Arrays.asList("132xxxxxxxx"));
// isAtAll类型如果不为Boolean,请升级至最新SDK
at.setIsAtAll(true);
at.setAtUserIds(Arrays.asList("109929","32099"));
request.setAt(at);

request.setMsgtype("link");
OapiRobotSendRequest.Link link = new OapiRobotSendRequest.Link();
link.setMessageUrl("https://www.dingtalk.com/");
link.setPicUrl("");
link.setTitle("时代的火车向前开");
link.setText("这个即将发布的新版本,创始人xx称它为红树林。而在此之前,每当面临重大升级,产品经理们都会取一个应景的代号,这一次,为什么是红树林");
request.setLink(link);

request.setMsgtype("markdown");
OapiRobotSendRequest.Markdown markdown = new OapiRobotSendRequest.Markdown();
markdown.setTitle("杭州天气");
markdown.setText("#### 杭州天气 @156xxxx8827\n" +
"> 9度,西北风1级,空气良89,相对温度73%\n\n" +
"> ![screenshot](https://gw.alicdn.com/tfs/TB1ut3xxbsrBKNjSZFpXXcXhFXa-846-786.png)\n" +
"> ###### 10点20分发布 [天气](http://www.thinkpage.cn/) \n");
request.setMarkdown(markdown);
OapiRobotSendResponse response = client.execute(request);

复制成功

PHP程序测试

<?php  
function request_by_curl($remote_server, $post_string) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $remote_server);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_HTTPHEADER, array ('Content-Type: application/json;charset=utf-8'));
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// 线下环境不用开启curl证书验证, 未调通情况可尝试添加该代码
// curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);
// curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0);
$data = curl_exec($ch);
curl_close($ch);
return $data;
}

$webhook = "https://oapi.dingtalk.com/robot/send?access_token=xxxxxx";
$message="我就是我, 是不一样的烟火";
$data = array ('msgtype' => 'text','text' => array ('content' => $message));
$data_string = json_encode($data);

$result = request_by_curl($webhook, $data_string);
echo $result;
?>

复制成功

消息类型及数据格式

  • text类型

    {
    "at": {
    "atMobiles ": [
    "180xxxxxx"
    ],
    "atUserIds ": [
    "user123"
    ],
    "isAtAll ": false
    },
    "text": {
    "content ": "我就是我, @XXX 是不一样的烟火"
    },
    "msgtype": "text"
    }

    复制成功

    参数

    参数类型

    是否必填

    必须

    msgtype

    String

    消息类型,此时固定为:text。

    content

    String

    消息内容。

    atMobiles

    Array

    被@人的手机号。


    注意 

    在content里添加@人的手机号。

    atUserIds

    Array

    被@人的用户userid。

    isAtAll

    Boolean

    是否@所有人。

  • link类型

    {
    "msgtype": "link",
    "link": {
    "text": "这个即将发布的新版本,创始人xx称它为红树林。而在此之前,每当面临重大升级,产品经理们都会取一个应景的代号,这一次,为什么是红树林",
    "title": "时代的火车向前开",
    "picUrl": "",
    "messageUrl": "https://www.dingtalk.com/s?__biz=MzA4NjMwMTA2Ng==&mid=2650316842&idx=1&sn=60da3ea2b29f1dcc43a7c8e4a7c97a16&scene=2&srcid=09189AnRJEdIiWVaKltFzNTw&from=timeline&isappinstalled=0&key=&ascene=2&uin=&devicetype=android-23&version=26031933&nettype=WIFI"
    }
    }

    复制成功

    参数

    参数类型

    是否必填

    说明

    msgtype

    String

    消息类型,此时固定为:link。

    title

    String

    消息标题。

    text

    String

    消息内容。如果太长只会部分展示。

    messageUrl

    String

    点击消息跳转的URL。

    picUrl

    String

    图片URL。

  • markdown类型

    {
    "msgtype": "markdown",
    "markdown": {
    "title":"杭州天气",
    "text": "#### 杭州天气 @150XXXXXXXX \n> 9度,西北风1级,空气良89,相对温度73%\n> ![screenshot](https://img.alicdn.com/tfs/TB1NwmBEL9TBuNjy1zbXXXpepXa-2400-1218.png)\n> ###### 10点20分发布 [天气](https://www.dingtalk.com) \n"
    },
    "at": {
    "atMobiles": [
    "150XXXXXXXX"
    ],
    "atUserIds ": [
    "user123"
    ],
    "isAtAll": false
    }
    }

    复制成功

    参数

    类型

    是否必填

    说明

    msgtype

    String

    消息类型,此时固定为:markdown。

    title

    String

    首屏会话透出的展示内容。

    text

    String

    markdown格式的消息。

    atMobiles

    Array

    被@人的手机号。


    注意 

    在text内容里要有@人的手机号。

    atUserIds

    Array

    被@人的用户userid。

    isAtAll

    Boolean

    是否@所有人。

    目前只支持markdown语法的子集,具体支持的元素如下:

    标题
    # 一级标题
    ## 二级标题
    ### 三级标题
    #### 四级标题
    ##### 五级标题
    ###### 六级标题

    引用
    > A man who stands for nothing will fall for anything.

    文字加粗、斜体
    **bold**
    *italic*

    链接
    [this is a link](http://name.com)

    图片
    ![](http://name.com/pic.jpg)

    无序列表
    - item1
    - item2

    有序列表
    1. item1
    2. item2

    复制成功

  • 整体跳转ActionCard类型

    {
    "actionCard": {
    "title": "乔布斯 20 年前想打造一间苹果咖啡厅,而它正是 Apple Store 的前身",
    "text": "![screenshot](https://gw.alicdn.com/tfs/TB1ut3xxbsrBKNjSZFpXXcXhFXa-846-786.png)
    ### 乔布斯 20 年前想打造的苹果咖啡厅
    Apple Store 的设计正从原来满满的科技感走向生活化,而其生活化的走向其实可以追溯到 20 年前苹果一个建立咖啡馆的计划",
    "btnOrientation": "0",
    "singleTitle" : "阅读全文",
    "singleURL" : "https://www.dingtalk.com/"
    },
    "msgtype": "actionCard"
    }

    复制成功

    参数

    类型

    是否必填

    说明

    msgtype

    String

    消息类型,此时固定为:actionCard。

    title

    String

    首屏会话透出的展示内容。

    text

    String

    markdown格式的消息。

    singleTitle

    String

    单个按钮的标题。


    注意 

    设置此项和singleURL后,btns无效。

    singleURL

    String

    点击singleTitle按钮触发的URL。

    btnOrientation

    String

    0:按钮竖直排列

    1:按钮横向排列

    通过整体跳转ActionCard类型消息发出的消息样式如下:

  • 独立跳转ActionCard类型

    {
    "msgtype": "actionCard",
    "actionCard": {
    "title": "我 20 年前想打造一间苹果咖啡厅,而它正是 Apple Store 的前身",
    "text": "![screenshot](https://img.alicdn.com/tfs/TB1NwmBEL9TBuNjy1zbXXXpepXa-2400-1218.png) \n\n #### 乔布斯 20 年前想打造的苹果咖啡厅 \n\n Apple Store 的设计正从原来满满的科技感走向生活化,而其生活化的走向其实可以追溯到 20 年前苹果一个建立咖啡馆的计划",
    "hideAvatar": "0",
    "btnOrientation": "0",
    "btns": [
    {
    "title": "内容不错",
    "actionURL": "https://www.dingtalk.com/"
    },
    {
    "title": "不感兴趣",
    "actionURL": "https://www.dingtalk.com/"
    }
    ]
    }
    }

    复制成功

    参数

    类型

    是否必填

    说明

    msgtype

    String

    此消息类型为固定actionCard。

    title

    String

    首屏会话透出的展示内容。

    text

    String

    markdown格式的消息。

    btns

    Array

    按钮。

    title

    String

    按钮标题。

    actionURL

    String

    点击按钮触发的URL。

    btnOrientation

    String

    0:按钮竖直排列

    1:按钮横向排列

    通过独立跳转ActionCard类型消息发出的消息样式如下:

  • FeedCard类型

    {
    "msgtype": "feedCard",
    "feedCard": {
    "links": [
    {
    "title": "时代的火车向前开1",
    "messageURL": "https://www.dingtalk.com/",
    "picURL": "https://img.alicdn.com/tfs/TB1NwmBEL9TBuNjy1zbXXXpepXa-2400-1218.png"
    },
    {
    "title": "时代的火车向前开2",
    "messageURL": "https://www.dingtalk.com/",
    "picURL": "https://img.alicdn.com/tfs/TB1NwmBEL9TBuNjy1zbXXXpepXa-2400-1218.png"
    }
    ]
    }
    }

    复制成功

    参数

    类型

    是否必填

    说明

    msgtype

    String

    此消息类型为固定feedCard。

    title

    String

    单条信息文本。

    messageURL

    String

    点击单条信息到跳转链接。

    picURL

    String

    单条信息后面图片的URL。

    通过FeedCard类型消息发出的消息样式如下:

常见问题

  1. 当出现以下错误时,表示消息校验未通过,请查看机器人的安全设置。

    // 消息内容中不包含任何关键词
    {
    "errcode":310000,
    "errmsg":"keywords not in content"
    }

    // timestamp 无效
    {
    "errcode":310000,
    "errmsg":"invalid timestamp"
    }

    // 签名不匹配
    {
    "errcode":310000,
    "errmsg":"sign not match"
    }

    // IP地址不在白名单
    {
    "errcode":310000,
    "errmsg":"ip X.X.X.X not in whitelist"
    }

    复制成功



浏览 97
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报