DingDing自定義機器人接入

和官方差不多,只是我把特別注意標註出來。

場景介紹

企業內部有較多系統支撐着公司的核心業務流程,譬如CRM系統、交易系統、監控報警系統等等。通過釘釘的自定義機器人,可以將這些系統事件同步到釘釘的聊天羣。

 
說明 

當前機器人尚不支持應答機制,該機制指的是羣裏成員在聊天@機器人的時候,釘釘回調指定的服務地址,即Outgoing機器人。

步驟一:獲取自定義機器人Webhook

  1. 打開機器人管理頁面。以PC端爲例,打開PC端釘釘,點擊頭像,選擇機器人管理。image.png

  2. 在機器人管理頁面選擇自定義機器人,輸入機器人名字並選擇要發送消息的羣,同時可以爲機器人設置機器人頭像。屏幕快照 2019-10-25 下午1.50.45.png

  3. 完成必要的安全設置,勾選我已閱讀並同意《自定義機器人服務及免責條款》,然後單擊完成。

    目前有3種安全設置方式,請根據需要選擇一種:

    • 自定義關鍵詞:最多可以設置10個關鍵詞,消息中至少包含其中1個關鍵詞纔可以發送成功。

      例如添加了一個自定義關鍵詞:監控報警,則這個機器人所發送的消息,必須包含監控報警這個詞,才能發送成功。

    • 加簽:

      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

        第一步得到的簽名值。

    • IP地址(段):設定後,只有來自IP地址範圍內的請求才會被正常處理。支持兩種設置方式:IP地址和IP地址段,暫不支持IPv6地址白名單,格式如下。

      格式

      說明

      1.1.1.1

      開發者的出口公網IP地址(非局域網地址)

      1.1.1.0/24

      用CIDR表示的一個網段

      image.png
  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":"我就是我, 是不一樣的煙火"}}'
注意:這裏的
"我就是我, 是不一樣的煙火",必須加上關鍵字
例子:
"hive我就是我, 是不一樣的煙火"

 

 

 

 

 

 

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

    是否@所有人。

    777.png
  • 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。

    image.png
  • 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

    是否@所有人。

    image.png

    目前只支持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類型消息發出的消息樣式如下:image.png

  • 獨立跳轉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類型消息發出的消息樣式如下:屏幕快照 2019-12-25 下午8.27.52.png

  • 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類型消息發出的消息樣式如下:屏幕快照 2019-12-25 下午8.29.45.png

常見問題

  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"
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章