本文将手把手教你如何在 Zabbix 7.0.16 中配置钉钉机器人 Webhook,实现告警信息自动推送到钉钉群。 脚本基于纯手搓编写,已实测可用。
一、钉钉机器人创建与获取参数
进入钉钉群 → 点击右上角 群设置 → 群智能助手与机器人 → 添加机器人。
选择 自定义机器人。
安全设置选择 加签(推荐,安全性高)。
创建后会获得:
Webhook URL(其中包含 access_token 参数值)
加签密钥(即 secret)
保存好:
access_token:在 Webhook URL 中 access_token=xxxx 的值
secret:加签时生成的密钥
二、Zabbix 创建Webhook 媒介类型、动作
进入 Zabbix 前端 → 管理 → 媒介类型 → 创建媒介类型
填写基本信息:
名称: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 +
"×tamp=" + 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等
所有参数从媒介类型的 参数表 传入,不要写死在脚本里。
四、创建动作绑定钉钉告警
进入 Zabbix 前端 → 配置 → 动作 → 创建一个动作(如“钉钉告警”)。
条件:选择需要触发告警的规则(如触发器严重性 ≥ 严重)。
操作:
操作类型:发送到用户
发送到:选择已配置了 DingdingWebhook 媒介的用户
消息模板:自定义告警内容
五、测试与验证
1. 测试媒介类型
在 媒介类型 → DingdingWebhook → 测试,填入:
Message: 测试一下钉钉告警
token: 你的 token
secret: 你的 secret
点击 测试,如果返回:
{"errcode":0,"errmsg":"ok"}
说明钉钉收到了消息。

2. 实际触发测试
制造一个触发器条件(如关闭某台主机的 Agent),触发告警后应能在钉钉群看到消息。
六、常见问题
undefined 或 null 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}×tamp=${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"
该脚本可以判断本地拼接函数是否和钉钉接口连通