場景介紹
企業內部有較多系統支撐着公司的核心業務流程,譬如CRM系統、交易系統、監控報警系統等等。通過釘釘的自定義機器人,可以將這些系統事件同步到釘釘的聊天羣。
當前機器人尚不支持應答機制,該機制指的是羣裏成員在聊天@機器人的時候,釘釘回調指定的服務地址,即Outgoing機器人。
步驟一:獲取自定義機器人Webhook
-
打開機器人管理頁面。以PC端爲例,打開PC端釘釘,點擊頭像,選擇機器人管理。
-
在機器人管理頁面選擇自定義機器人,輸入機器人名字並選擇要發送消息的羣,同時可以爲機器人設置機器人頭像。
-
完成必要的安全設置,勾選我已閱讀並同意《自定義機器人服務及免責條款》,然後單擊完成。
目前有3種安全設置方式,請根據需要選擇一種:
-
自定義關鍵詞:最多可以設置10個關鍵詞,消息中至少包含其中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)
-
把 timestamp和第一步得到的簽名值拼接到URL中。
https://oapi.dingtalk.com/robot/send?access_token=XXXXXX×tamp=XXX&sign=XXX
參數
說明
timestamp
第一步使用到的時間戳。
sign
第一步得到的簽名值。
-
-
IP地址(段):設定後,只有來自IP地址範圍內的請求才會被正常處理。支持兩種設置方式:IP地址和IP地址段,暫不支持IPv6地址白名單,格式如下。
格式
說明
1.1.1.1
開發者的出口公網IP地址(非局域網地址)
1.1.1.0/24
用CIDR表示的一個網段
-
-
完成安全設置後,複製出機器人的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
否
是否@所有人。
-
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類型消息發出的消息樣式如下:
常見問題
-
當出現以下錯誤時,表示消息校驗未通過,請查看機器人的安全設置。
// 消息內容中不包含任何關鍵詞 { "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" }