遇到 401 错误,通常是因为钉钉机器人的安全设置(签名、关键词或 IP 白名单)与请求参数不匹配,或者 Webhook 地址本身已失效。
先说结论:优先检查机器人后台的安全设置类型,确保 Python 代码中携带了正确的签名参数或关键词。
- 先确认:登录钉钉管理后台,查看机器人安全设置是关键词、签名还是 IP 白名单。
- 先处理:根据安全类型修改 Python 请求代码,签名模式需计算 timestamp 和 sign。
- 再验证:发送测试消息,确认返回 JSON 中 errcode 为 0。
快速处理思路
import requests
import hmac
import hashlib
import base64
import urllib.parse
import time
# 替换为你的实际配置
webhook_url = 'https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN'
secret = 'YOUR_SECRET'
# 生成签名
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))
# 拼接完整 URL
url = '{}×tamp={}&sign={}'.format(webhook_url, timestamp, sign)
# 发送请求
headers = {'Content-Type': 'application/json'}
data = {'msgtype': 'text', 'text': {'content': '测试消息'}}
response = requests.post(url, json=data, headers=headers)
print(response.text)为什么会这样
HTTP 状态码 401 代表未经授权。在钉钉机器人场景中,这通常不是指账号密码错误,而是指 webhook 请求未通过安全校验。钉钉自定义机器人支持三种安全设置:自定义关键词、IP 地址白名单、签名校验。
如果后台开启了签名校验,而请求 URL 中缺少 timestamp 和 sign 参数,或者计算错误,服务端会直接拒绝请求。此外,如果请求头 Content-Type 不是 application/json,或者机器人已被禁用,也可能导致类似授权失败的响应。
分步处理
1. 核对安全设置
登录钉钉管理后台,进入机器人配置页面。确认当前启用的安全方式。如果是关键词,消息内容必须包含该词;如果是签名,必须按算法生成参数。
2. 检查代码实现
确保使用 HMAC-SHA256 算法。注意 timestamp 单位是毫秒。secret 必须与后台显示完全一致,不要多复制空格。
3. 确认请求头
使用 Python requests 库时,json 参数会自动设置 Content-Type,但手动构造 body 时需显式添加 headers={'Content-Type': 'application/json'}。
4. 检查机器人状态
确认机器人未被管理员禁用或删除。如果 webhook 地址中的 access_token 已变更,需重新复制新地址。
怎么验证是否生效
运行代码后,观察响应内容。钉钉接口通常返回 HTTP 200,但业务状态在 JSON body 中。
成功标志:返回 JSON 中包含 "errcode": 0 和 "errmsg": "ok"。
失败标志:如果仍然返回 401 或 JSON 中 errcode 非 0,查看 errmsg 提示。常见提示包括“签名无效”、“关键词不匹配”等。
常见坑
1. 时间戳单位错误
钉钉要求毫秒级时间戳,Python 中 time.time() 是秒,需乘以 1000 并取整。
2. 换行符差异
签名字符串拼接时,timestamp 和 secret 之间必须是换行符 \n,不能是空格或其他字符。
3. URL 编码问题
计算出的 sign 包含特殊字符,必须进行 URL encode(如 quote_plus),否则请求会被拦截。
4. 密钥复制错误
后台显示的 secret 可能包含前后空格,复制时需仔细检查,建议在代码中打印长度核对。
参考来源
- 钉钉开放平台 - 自定义机器人接入,https://open.dingtalk.com/document/robots/custom-robot-access
- 钉钉开放平台 - 签名校验算法说明,https://open.dingtalk.com/document/robots/signature-validation