本文将手把手教你如何在 Zabbix 7.0.16 中配置钉钉机器人 Webhook,实现告警信息自动推送到钉钉群。 脚本基于纯手搓编写,已实测可用。

一、钉钉机器人创建与获取参数

  1. 进入钉钉群 → 点击右上角 群设置群智能助手与机器人 → 添加机器人。

  2. 选择 自定义机器人

  3. 安全设置选择 加签(推荐,安全性高)。

  4. 创建后会获得:

Webhook URL(其中包含 access_token 参数值)

加签密钥(即 secret

保存好:

access_token:在 Webhook URL 中 access_token=xxxx 的值

secret:加签时生成的密钥

二、Zabbix 创建Webhook 媒介类型、动作

  1. 进入 Zabbix 前端管理媒介类型创建媒介类型

  2. 填写基本信息:

名称:DingdingWebhook

类型:Webhook

脚本语言:JavaScript

添加脚本参数(注意顺序一致):

Message{ALERT.MESSAGE}

token → 你的 access_token

secret → 你的 secret

在脚本编辑框中粘贴下面的代码

三、可用的 DingTalk Webhook 脚本(Zabbix JavaScript 版本)

// Zabbix 7.0+ 钉钉加签 Webhook(Duktape可运行)

// 参数表格:Message / secret / token

// --- URL encode ---

function urlencode(str){

return encodeURIComponent(str)

.replace(/!/g,'%21').replace(/'/g,'%27')

.replace(/\(/g,'%28').replace(/\)/g,'%29')

.replace(/\*/g,'%2A');

}

// --- Base64 编码(bytes -> base64字符串)---

function b64encode(bytes){

var chars="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

var out="", i=0, len=bytes.length, r=len%3, m=len-r;

for(; i<m; i+=3){

var n=(bytes[i]<<16)|(bytes[i+1]<<8)|bytes[i+2];

out+=chars[(n>>>18)&63]+chars[(n>>>12)&63]+chars[(n>>>6)&63]+chars[n&63];

}

if(r===1){

var n1=bytes[m]<<16;

out+=chars[(n1>>>18)&63]+chars[(n1>>>12)&63]+"==";

}else if(r===2){

var n2=(bytes[m]<<16)|(bytes[m+1]<<8);

out+=chars[(n2>>>18)&63]+chars[(n2>>>12)&63]+chars[(n2>>>6)&63]+"=";

}

return out;

}

// --- UTF8 编码(string -> bytes)---

function utf8Bytes(str){

var u=unescape(encodeURIComponent(str)), a=[], i;

for(i=0;i<u.length;i++) a.push(u.charCodeAt(i));

return a;

}

// --- SHA-256(bytes -> bytes)---

function sha256(bytes){

function rotr(x,n){ return (x>>>n) | (x<<(32-n)); }

function ch(x,y,z){ return (x & y) ^ (~x & z); }

function maj(x,y,z){ return (x & y) ^ (x & z) ^ (y & z); }

function bs0(x){ return rotr(x,2)^rotr(x,13)^rotr(x,22); }

function bs1(x){ return rotr(x,6)^rotr(x,11)^rotr(x,25); }

function ss0(x){ return rotr(x,7)^rotr(x,18)^(x>>>3); }

function ss1(x){ return rotr(x,17)^rotr(x,19)^(x>>>10); }

var K=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,

3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,

3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,

2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,

666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,

2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,

430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,

1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298];

var H=[1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225];

// padding

var l=bytes.length, m=bytes.slice(0); m.push(0x80);

while(((m.length+8)&63)!==0) m.push(0);

var bitHi = Math.floor((l>>>29)>>>0), bitLo=(l<<3)>>>0;

m.push((bitHi>>>24)&255,(bitHi>>>16)&255,(bitHi>>>8)&255,bitHi&255,

(bitLo>>>24)&255,(bitLo>>>16)&255,(bitLo>>>8)&255,bitLo&255);

for(var i=0;i<m.length;i+=64){

var w=new Array(64), j;

for(j=0;j<16;j++){

var k=i+j*4; w[j]=((m[k]<<24)|(m[k+1]<<16)|(m[k+2]<<8)|m[k+3])>>>0;

}

for(j=16;j<64;j++) w[j]=(ss1(w[j-2])+w[j-7]+ss0(w[j-15])+w[j-16])>>>0;

var a=H[0],b=H[1],c=H[2],d=H[3],e=H[4],f=H[5],g=H[6],h=H[7];

for(j=0;j<64;j++){

var T1=(h+bs1(e)+ch(e,f,g)+K[j]+w[j])>>>0;

var T2=(bs0(a)+maj(a,b,c))>>>0;

h=g; g=f; f=e; e=(d+T1)>>>0; d=c; c=b; b=a; a=(T1+T2)>>>0;

}

H[0]=(H[0]+a)>>>0; H[1]=(H[1]+b)>>>0; H[2]=(H[2]+c)>>>0; H[3]=(H[3]+d)>>>0;

H[4]=(H[4]+e)>>>0; H[5]=(H[5]+f)>>>0; H[6]=(H[6]+g)>>>0; H[7]=(H[7]+h)>>>0;

}

var out=[], x;

for(x=0;x<8;x++){

out.push((H[x]>>>24)&255,(H[x]>>>16)&255,(H[x]>>>8)&255,H[x]&255);

}

return out;

}

// --- HMAC-SHA256(key/message均为字符串,返回bytes)---

function hmacSHA256(keyStr, msgStr){

var block=64;

var key=utf8Bytes(keyStr);

if(key.length>block){ key=sha256(key); }

while(key.length<block) key.push(0);

var o=[], i=[], t;

for(t=0;t<block;t++){ o[t]=key[t]^0x5c; i[t]=key[t]^0x36; }

var inner = sha256(i.concat(utf8Bytes(msgStr)));

var h = sha256(o.concat(inner));

return h;

}

try{

// 1) 读取参数(来自参数表格)

if (typeof value !== 'string' || !value) {

throw 'Params "value" is empty (check media type Parameters).';

}

var params = JSON.parse(value);

var message = (params.Message || params.message || 'Zabbix alert');

var secret = (params.secret || '').replace(/^\s+|\s+$/g,'');

var token = (params.token || '').replace(/^\s+|\s+$/g,'');

if (!secret || !token) {

throw 'Missing parameter: token/secret';

}

// 2) 计算签名

var timestamp = Date.now();

var stringToSign = timestamp + "\n" + secret;

var signBytes = hmacSHA256(secret, stringToSign);

var sign = urlencode(b64encode(signBytes));

// 3) 发送

var url = "https://oapi.dingtalk.com/robot/send?access_token=" + token +

"&timestamp=" + timestamp + "&sign=" + sign;

var payload = { msgtype: "text", text: { content: message } };

var req = new HttpRequest();

req.addHeader("Content-Type: application/json");

var resp = req.post(url, JSON.stringify(payload));

// 调试日志(屏蔽 token)

Zabbix.log(4, "[DingTalk] POST " + url.replace(token, "***") +

" code=" + req.getStatus() + " resp=" + resp);

if (req.getStatus() < 200 || req.getStatus() >= 300) {

throw "HTTP " + req.getStatus() + ": " + resp;

}

return resp;

}catch(e){

Zabbix.log(3, "[DingTalk] ERROR: " + e);

throw e;

}

说明:

  • 所有函数均为手搓,算法、HAS等

  • 所有参数从媒介类型的 参数表 传入,不要写死在脚本里。

四、创建动作绑定钉钉告警

  1. 进入 Zabbix 前端配置动作 → 创建一个动作(如“钉钉告警”)。

  2. 条件:选择需要触发告警的规则(如触发器严重性 ≥ 严重)。

  3. 操作:

操作类型:发送到用户

发送到:选择已配置了 DingdingWebhook 媒介的用户

消息模板:自定义告警内容

五、测试与验证

1. 测试媒介类型

媒介类型DingdingWebhook测试,填入:

Message: 测试一下钉钉告警

token: 你的 token

secret: 你的 secret

点击 测试,如果返回:

{"errcode":0,"errmsg":"ok"}

说明钉钉收到了消息。

2. 实际触发测试

制造一个触发器条件(如关闭某台主机的 Agent),触发告警后应能在钉钉群看到消息。

六、常见问题

undefinednull given 错误:通常是因为参数没传进脚本,检查媒介类型参数表。

ReferenceError: identifier 'CryptoJS' undefined:Zabbix 的 JavaScript 不能直接用外部库,要用内置 hmac_sha256,或者手搓

param error:可能是 timestamp 与服务器时间差太大,确认 Zabbix 服务器时间正确。

7、附件(本地测试脚本)

#!/bin/bash

# ======= 修改成你的 token 和 secret =======

access_token="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

secret="SECxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

# ======= 生成签名 =======

timestamp=$(($(date +%s%N)/1000000))

string_to_sign="${timestamp}\n${secret}"

sign=$(echo -en "$string_to_sign" | openssl dgst -sha256 -hmac "$secret" -binary | base64)

sign=$(python3 -c "import urllib.parse; print(urllib.parse.quote('''$sign'''))")

# 拼 URL

url="https://oapi.dingtalk.com/robot/send?access_token=${access_token}&timestamp=${timestamp}&sign=${sign}"

echo "Webhook URL:"

echo "$url"

# ======= 发送消息 =======

resp=$(curl -s "$url" \

-H 'Content-Type: application/json' \

-d '{"msgtype": "text", "text": {"content": "本地测试钉钉机器人"}}')

echo "返回结果:"

echo "$resp"

该脚本可以判断本地拼接函数是否和钉钉接口连通

0%