钉钉机器人webhook需加timestamp和sign签名,用hmac-sha256计算"${timestamp}\n${secret}"再base64编码;飞书发富文本须设content-type: application/json,at需独立字段,非text内嵌。

钉钉机器人 Webhook URL 怎么加签名验证才不被拒
直接用裸 URL 发告警,大概率收不到——钉钉强制要求 timestamp 和 sign 参数(除非你关了「加签」,但生产环境不建议)。签名不是简单拼接,得用 HMAC-SHA256 对 "${timestamp}\n${secret}" 计算,再 Base64 编码。
Shell 里没原生 HMAC 函数,得靠 openssl 配合 echo -n(注意 -n,否则换行符多一个就验不过):
timestamp=$(date +%s%3N)
secret="your_secret_here"
sign=$(echo -n "${timestamp}\n${secret}" | openssl sha256 -hmac "${secret}" | awk '{print $NF}' | xxd -r -p | base64)
常见坑:
-
date +%s%3N在部分老版 busybox 或 Alpine 的date不支持 %3N,得用$(($(date +%s%N)/1000000))替代 -
openssl sha256 -hmac在 macOS 的 OpenSSL 版本可能不认-hmac,要换成openssl dgst -sha256 -hmac - URL 里空格或特殊字符没 urlencode,
curl会截断,必须用printf '%s' "$url" | jq -sRr @uri(需装jq)或手动替换
飞书机器人怎么发富文本(text + at 某人)且不报 400
飞书要求 Content-Type: application/json,且 payload 必须是合法 JSON,字段名大小写敏感(比如是 msg_type,不是 msgType),at 不是写在 text 里,得单独放 at 字段里。
典型能跑通的最小结构:
cat <p>关键点:</p>
-
user_id不是手机号或邮箱,得从飞书管理后台「成员详情」里复制,格式类似ou_abc123... - 如果想 at 全体,
user_id改成all,但机器人必须有「发送 at 全体消息」权限(管理员开) - 中文字段名(如
zh_cn)漏掉或写错,返回{"code":400,"msg":"invalid request"},没更多提示
Shell 脚本里怎么统一处理钉钉/飞书失败重试和超时
网络抖动或机器人限流(钉钉 20次/分钟,飞书 60次/分钟)会导致 curl 返回非 2xx,但默认不报错。得用 -f(fail on error)+ -s(silent)+ -o /dev/null,再检查 $? 和响应体。
飞书任务管理工具,支持任务的创建、查询、更新、删除及清单的管理。适用场景:创建/管理任务与清单、查看任务列表或清单中的任务、用户提及任务、待办、to‑do、清单、task时、设置负责人和关注等。
推荐封装一个带重试的发信函数:
send_alert() {
local url=$1 msg=$2 max_retry=3
for i in $(seq 1 $max_retry); do
response=$(curl -sf -o /dev/null -w "%{http_code}" -m 10 "$url" -d "$msg")
if [ "$response" = "200" ]; then
return 0
elif [ $i -eq $max_retry ]; then
echo "alert failed after $max_retry tries: HTTP $response" >&2
return 1
fi
sleep $((i * 2))
done
}
注意:
-
-m 10是总超时(含 DNS、连接、传输),别设太短,否则弱网下必失败 - 飞书返回成功是
200,但钉钉是{"errcode":0,...},所以不能只看 HTTP 状态码,还得解析 body(建议加jq -e '.errcode == 0'判断) - 重试间隔递增(
$((i * 2))),避免雪崩式重试打满配额
告警内容里怎么安全注入变量又不被 XSS 或 JSON 格式破坏
Shell 变量直接拼进 JSON,遇到双引号、反斜杠、换行就会让 JSON 解析失败;更糟的是,如果变量来自日志或命令输出,还可能带恶意内容。
最稳的方式是用 jq 构造 payload:
payload=$(jq -n \
--arg title "$TITLE" \
--arg text "$ALERT_TEXT" \
--arg level "$LEVEL" \
'{
msg_type: "post",
content: {
post: {
zh_cn: {
title: $title,
content: [[{"tag": "text", "text": $text}]]
}
}
}
}')
这样所有变量自动 JSON 转义,包括 \n、"、€ 都没问题。没装 jq?别手写 escape——临时用 Python 一行也比正则可靠:
payload=$(python3 -c "import json,sys; print(json.dumps({'text': sys.argv[1]}, ensure_ascii=False))" "$ALERT_TEXT")
别忘了:ALERT_TEXT 如果含未转义的 $ 或 `,在 eval 或未引号的 echo 里会被 Shell 展开,务必全程用 "$var" 包裹。
复杂点在于飞书的 at 和钉钉的 atMobiles 字段都要动态填,而用户 ID 本身也可能含特殊字符——这时候 jq --argjson 或预处理成数组更稳妥,别贪快拼字符串。










