为什么钉钉机器人发送消息成功但群里不显示可能的原因

文章导读
大多数情况下,这是因为安全设置(关键词或签名)不匹配,或者触发了频率限制,导致接口返回 HTTP 200 但业务逻辑失败。
📋 目录
  1. 命令速用版
  2. 为什么会这样
  3. 分步处理
  4. 怎么验证是否生效
  5. 常见坑
  6. 参考来源
A A

大多数情况下,这是因为安全设置(关键词或签名)不匹配,或者触发了频率限制,导致接口返回 HTTP 200 但业务逻辑失败。

先说结论:接口请求成功不代表消息送达,需优先检查返回 body 中的 errcode 及群机器人安全设置。

  • 先确认:接口响应 body 中 errcode 是否为 0
  • 先处理:核对 webhook 地址与安全设置(关键词/签名)
  • 再验证:手动发送测试消息确认群内显示

命令速用版

使用 curl 直接测试 webhook,避免代码封装掩盖真实响应:

curl 'https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN' \
-H 'Content-Type: application/json' \
-d '{"msgtype":"text","text":{"content":"测试消息"}}'

执行后直接观察终端输出的 JSON 响应,重点看 errcode 字段。

为什么会这样

很多开发者误以为 HTTP 状态码 200 就代表消息发送成功。实际上,钉钉开放平台接口在请求合法到达服务器时就会返回 200,但业务是否成功取决于返回 body 中的 errcode。

常见原因包括:

  • 安全设置不匹配:群机器人开启了关键词过滤或签名验证,但请求内容未包含关键词或签名计算错误。
  • 频率限制:短时间内发送过多消息,触发官方频率控制策略。
  • 机器人状态异常:机器人已被移除群聊或被管理员禁用,但 webhook 地址未变。
  • 内容过滤:消息内容包含敏感词,被系统拦截。

分步处理

1. 检查接口响应体

为什么钉钉机器人发送消息成功但群里不显示可能的原因

不要只判断 HTTP 状态码。确保你的代码解析了响应 JSON,并判断 errcode 是否为 0。如果 errcode 不为 0,根据 errmsg 提示修改。

2. 核对安全设置

登录钉钉群设置,找到机器人详情,检查安全设置:

  • 关键词:确保发送内容中完整包含设置的关键词(区分大小写)。
  • 签名:如果开启了签名,必须按文档要求计算 timestamp 和 sign,并拼接到 access_token 后。
  • IP 白名单:如果设置了白名单,确保服务器出口 IP 在列表内。

以下是常见语言的签名计算示例(secret 为机器人安全设置中的密钥):

Python 示例:

import time, hmac, hashlib, base64, urllib.parse

secret = 'SEC...'
timestamp = str(round(time.time() * 1000))
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))
webhook = 'https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN×tamp={}&sign={}'.format(timestamp, sign)

Java 示例:

Long timestamp = System.currentTimeMillis();
String secret = "SEC...";
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");
String webhook = "https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN×tamp=" + timestamp + "&sign=" + sign;

Node.js 示例:

为什么钉钉机器人发送消息成功但群里不显示可能的原因
const crypto = require('crypto');
const secret = 'SEC...';
const timestamp = Date.now().toString();
const stringToSign = timestamp + '\n' + secret;
const sign = crypto.createHmac('sha256', secret).update(stringToSign).digest('base64');
const encodedSign = encodeURIComponent(sign);
const webhook = `https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN×tamp=${timestamp}&sign=${encodedSign}`;

3. 检查发送频率

如果 errcode 提示频率限制,需要降低发送频次。官方文档通常建议控制在每分钟 20 条以内,具体请以最新文档为准,建议增加重试机制和间隔。

4. 确认机器人状态

在群内查看机器人是否在成员列表中。如果被移除,需要重新添加并获取新的 webhook 地址。

怎么验证是否生效

完成上述调整后,使用命令速用版中的 curl 命令发送一条纯文本测试消息。

验证标准:

  • curl 返回 errcode 为 0。
  • 钉钉群聊界面立即出现该条测试消息。
  • 消息内容与发送内容一致,无乱码或缺失。

常见坑

  • 签名计算错误:签名需要使用 HMAC-SHA256 算法,且 timestamp 单位为毫秒,拼接格式必须严格符合文档要求。
  • 关键词匹配:关键词是包含关系,但必须完全匹配,例如设置“报警”,内容含“报警通知”可以,但“警”不行。
  • HTTPS 证书:部分服务器环境请求 HTTPS 接口时未验证证书导致请求被拦截,确保 curl 或代码中 SSL 验证正常。
  • 复制错误:webhook 地址中的 access_token 容易复制不全或混入空格,导致认证失败。

参考来源

  • 钉钉开放平台,自定义机器人接入,https://open.dingtalk.com/document/orgapp/custom-robot-access
  • 钉钉开放平台,机器人消息发送频率说明,https://open.dingtalk.com/document/orgapp/custom-bot-send-message-type