收藏系列-告警接入釘釘
場景介紹
企業(yè)內部有較多系統(tǒng)支撐著公司的核心業(yè)務流程,譬如CRM系統(tǒng)、交易系統(tǒng)、監(jiān)控報警系統(tǒng)等等。通過釘釘?shù)淖远x機器人,可以將這些系統(tǒng)事件同步到釘釘?shù)牧奶烊骸?/p>
說明
當前機器人尚不支持應答機制,該機制指的是群里成員在聊天@機器人的時候,釘釘回調指定的服務地址,即Outgoing機器人。
步驟一:獲取自定義機器人Webhook
打開機器人管理頁面。以PC端為例,打開PC端釘釘,點擊頭像,選擇機器人管理。

在機器人管理頁面選擇自定義機器人,輸入機器人名字并選擇要發(fā)送消息的群,同時可以為機器人設置機器人頭像。

完成必要的安全設置,勾選我已閱讀并同意《自定義機器人服務及免責條款》,然后單擊完成。
目前有3種安全設置方式,請根據(jù)需要選擇一種:
自定義關鍵詞:最多可以設置10個關鍵詞,消息中至少包含其中1個關鍵詞才可以發(fā)送成功。
例如添加了一個自定義關鍵詞:監(jiān)控報警,則這個機器人所發(fā)送的消息,必須包含監(jiān)控報警這個詞,才能發(fā)送成功。
加簽:
IP地址(段):設定后,只有來自IP地址范圍內的請求才會被正常處理。支持兩種設置方式:IP地址和IP地址段,暫不支持IPv6地址白名單,格式如下。
格式
說明
1.1.1.1
開發(fā)者的出口公網(wǎng)IP地址(非局域網(wǎng)地址)
1.1.1.0/24
用CIDR表示的一個網(wǎng)段

把
timestamp+"\n"+密鑰當做簽名字符串,使用HmacSHA256算法計算簽名,然后進行Base64 encode,最后再把簽名參數(shù)再進行urlEncode,得到最終的簽名(需要使用UTF-8字符集)。參數(shù)
說明
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復制成功
參數(shù)
說明
timestamp
第一步使用到的時間戳。
sign
第一步得到的簽名值。
完成安全設置后,復制出機器人的Webhook地址,可用于向這個群發(fā)送消息,格式如下:
https://oapi.dingtalk.com/robot/send?access_token=XXXXXX復制成功
注意
請保管好此Webhook 地址,不要公布在外部網(wǎng)站上,泄露后有安全風險。
步驟二:使用自定義機器人
獲取到Webhook地址后,用戶可以向這個地址發(fā)起HTTP POST 請求,即可實現(xiàn)給該釘釘群發(fā)送消息。
注意
發(fā)起POST請求時,必須將字符集編碼設置成UTF-8。
每個機器人每分鐘最多發(fā)送20條。消息發(fā)送太頻繁會嚴重影響群成員的使用體驗,大量發(fā)消息的場景 (譬如系統(tǒng)監(jiān)控報警) 可以將這些信息進行整合,通過markdown消息以摘要的形式發(fā)送到群里。
當前自定義機器人支持文本 (text)、鏈接 (link)、markdown(markdown)、ActionCard、FeedCard消息類型,請根據(jù)自己的使用場景選擇合適的消息類型,達到最好的展示樣式。詳情參考:消息類型及數(shù)據(jù)格式。
自定義機器人發(fā)送消息時,可以通過手機號碼指定“被@人列表”。在“被@人列表”里面的人員收到該消息時,會有@消息提醒。免打擾會話仍然通知提醒,首屏出現(xiàn)“有人@你”。
步驟三:測試自定義機器人
通過以下方法,可以快速驗證自定義機器人是否可以正常工作:
使用命令行工具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("這個即將發(fā)布的新版本,創(chuàng)始人xx稱它為紅樹林。而在此之前,每當面臨重大升級,產品經(jīng)理們都會取一個應景的代號,這一次,為什么是紅樹林");
request.setLink(link);
request.setMsgtype("markdown");
OapiRobotSendRequest.Markdown markdown = new OapiRobotSendRequest.Markdown();
markdown.setTitle("杭州天氣");
markdown.setText("#### 杭州天氣 @156xxxx8827\n" +
"> 9度,西北風1級,空氣良89,相對溫度73%\n\n" +
"> \n" +
"> ###### 10點20分發(fā)布 [天氣](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);
// 線下環(huán)境不用開啟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;
?>復制成功
消息類型及數(shù)據(jù)格式
text類型
{
"at": {
"atMobiles ": [
"180xxxxxx"
],
"atUserIds ": [
"user123"
],
"isAtAll ": false
},
"text": {
"content ": "我就是我, @XXX 是不一樣的煙火"
},
"msgtype": "text"
}復制成功
參數(shù)
參數(shù)類型
是否必填
必須
msgtype
String
是
消息類型,此時固定為:text。
content
String
是
消息內容。
atMobiles
Array
否
被@人的手機號。
注意
在content里添加@人的手機號。
atUserIds
Array
否
被@人的用戶userid。
isAtAll
Boolean
否
是否@所有人。

link類型
{
"msgtype": "link",
"link": {
"text": "這個即將發(fā)布的新版本,創(chuàng)始人xx稱它為紅樹林。而在此之前,每當面臨重大升級,產品經(jīng)理們都會取一個應景的代號,這一次,為什么是紅樹林",
"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"
}
}復制成功
參數(shù)
參數(shù)類型
是否必填
說明
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> \n> ###### 10點20分發(fā)布 [天氣](https://www.dingtalk.com) \n"
},
"at": {
"atMobiles": [
"150XXXXXXXX"
],
"atUserIds ": [
"user123"
],
"isAtAll": false
}
}復制成功
參數(shù)
類型
是否必填
說明
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)
圖片

無序列表
- item1
- item2
有序列表
1. item1
2. item2復制成功
整體跳轉ActionCard類型
{
"actionCard": {
"title": "喬布斯 20 年前想打造一間蘋果咖啡廳,而它正是 Apple Store 的前身",
"text": "
### 喬布斯 20 年前想打造的蘋果咖啡廳
Apple Store 的設計正從原來滿滿的科技感走向生活化,而其生活化的走向其實可以追溯到 20 年前蘋果一個建立咖啡館的計劃",
"btnOrientation": "0",
"singleTitle" : "閱讀全文",
"singleURL" : "https://www.dingtalk.com/"
},
"msgtype": "actionCard"
}復制成功
參數(shù)
類型
是否必填
說明
msgtype
String
是
消息類型,此時固定為:actionCard。
title
String
是
首屏會話透出的展示內容。
text
String
是
markdown格式的消息。
singleTitle
String
是
單個按鈕的標題。
注意
設置此項和singleURL后,btns無效。
singleURL
String
是
點擊singleTitle按鈕觸發(fā)的URL。
btnOrientation
String
否
0:按鈕豎直排列
1:按鈕橫向排列
通過整體跳轉ActionCard類型消息發(fā)出的消息樣式如下:

獨立跳轉ActionCard類型
{
"msgtype": "actionCard",
"actionCard": {
"title": "我 20 年前想打造一間蘋果咖啡廳,而它正是 Apple Store 的前身",
"text": " \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/"
}
]
}
}復制成功
參數(shù)
類型
是否必填
說明
msgtype
String
是
此消息類型為固定actionCard。
title
String
是
首屏會話透出的展示內容。
text
String
是
markdown格式的消息。
btns
Array
是
按鈕。
title
String
是
按鈕標題。
actionURL
String
是
點擊按鈕觸發(fā)的URL。
btnOrientation
String
否
0:按鈕豎直排列
1:按鈕橫向排列
通過獨立跳轉ActionCard類型消息發(fā)出的消息樣式如下:

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"
}
]
}
}復制成功
參數(shù)
類型
是否必填
說明
msgtype
String
是
此消息類型為固定feedCard。
title
String
是
單條信息文本。
messageURL
String
是
點擊單條信息到跳轉鏈接。
picURL
String
是
單條信息后面圖片的URL。
通過FeedCard類型消息發(fā)出的消息樣式如下:

常見問題
當出現(xiàn)以下錯誤時,表示消息校驗未通過,請查看機器人的安全設置。
// 消息內容中不包含任何關鍵詞
{
"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"
}復制成功
