dingtalk-chat-bot
v1.1.1
Published
Small helper for DingTalk app robot private and group chat messages, with built-in custom-robot signed-webhook support and ready-to-use example replies.
Readme
dingtalk-chat-bot
钉钉机器人工具包,封装 HTTP 回调签名校验、同步回复消息体、单聊发送、群聊发送,以及固定群机器人 Webhook 主动推送。
支持范围
这个包当前支持 HTTP 回调方式,不支持 Stream 长连接方式。
钉钉机器人常见有两类接入:
- HTTP 回调:钉钉把用户消息 POST 到你的公网服务。
- Stream 长连接:你的程序主动连接钉钉并保持长连接。
本包适合这些场景:
- 用户私聊机器人后,自动回复或异步发送单聊消息。
- 群里 @ 机器人后,回复当前群聊。
- 监控告警、定时日报等任务,通过固定群机器人 Webhook 主动推送到群。
本包暂不包含:
- Stream 长连接收消息。
- 业务指令解析。
- 数据库、任务队列、权限系统。
安装
npm install dingtalk-chat-bot创建实例
const { createDingTalkBot } = require("dingtalk-chat-bot");
const bot = createDingTalkBot({
appKey: process.env.DINGTALK_APP_KEY,
appSecret: process.env.DINGTALK_APP_SECRET,
robotCode: process.env.DINGTALK_ROBOT_CODE,
});配置说明:
appKey:钉钉应用的 AppKey。发送单聊消息时需要。appSecret:钉钉应用的 AppSecret。校验 HTTP 回调签名、获取 accessToken 时需要。robotCode:机器人编码。通常可以填 AppKey;如果钉钉后台单独展示 robotCode,就填 robotCode。webhookSecret:可选,自定义机器人「加签」安全策略的密钥(SEC 开头)。设置后sendWebhookMessage会自动按官方算法拼timestamp和sign。详见下方「自定义机器人加签」一节。httpClient:可选,自定义 HTTP 客户端,默认使用axios。signatureExpiresIn:可选,HTTP 回调签名时间窗口,默认 1 小时。
如果你只使用固定群机器人 Webhook 推送,可以不传 appKey、appSecret:
const bot = createDingTalkBot();
await bot.sendWebhookMessage(process.env.DINGTALK_WEBHOOK_URL, "服务正常");环境变量
仓库提供了 .env.example 作为模板。本地运行示例服务时,可以自己创建 .env:
cp .env.example .env示例:
PORT=3000
DINGTALK_APP_KEY=
DINGTALK_APP_SECRET=
DINGTALK_ROBOT_CODE=
DINGTALK_WEBHOOK_URL=.env 不应该提交到 Git,也不会进入 npm 发布包。
HTTP 回调签名校验
当钉钉把消息 POST 到你的服务时,可以这样校验签名:
app.post("/dingtalk/robot", async (req, res) => {
const ok = bot.verifySignature(req.headers.timestamp, req.headers.sign);
if (!ok) {
return res.status(401).json({ error: "invalid dingtalk signature" });
}
res.json(bot.buildReplyPayload("收到", req.body));
});同步回复
buildReplyPayload 用来构造可直接返回给钉钉 HTTP 回调的消息体。
普通文本:
res.json(bot.buildReplyPayload("你好,我收到了", req.body));Markdown:
res.json(bot.buildReplyPayload({
msgtype: "markdown",
title: "处理结果",
content: [
"## 处理结果",
"",
"- 状态:成功",
"- 耗时:120ms",
].join("\n"),
}, req.body));如果是群聊回调,并且消息体里有 senderStaffId,回复会默认在第一行真实 @ 提问人。
自动发送单聊或群聊
sendMessage 适合在收到钉钉回调后使用。它会根据回调消息体里的 conversationType 自动判断发送方式:
conversationType === "1":通过 OpenAPI 发送单聊消息。conversationType === "2":通过回调里的sessionWebhook发送群聊消息。
await bot.sendMessage(req.body, "这条消息会自动发到当前单聊或群聊");群聊发送时默认会 @ 本次提问人。如果不想 @:
await bot.sendMessage(req.body, "这条群消息不艾特任何人", {
atSender: false,
});发送 Markdown:
await bot.sendMessage(req.body, {
msgtype: "markdown",
title: "日报",
content: [
"## 今日日报",
"",
"- 完成机器人回复",
"- 支持单聊和群聊",
].join("\n"),
});主动发送单聊
await bot.sendPrivateMessage("用户 staffId", "你好");多个用户:
await bot.sendPrivateMessage(["staffId1", "staffId2"], "批量单聊消息");Markdown 单聊:
await bot.sendPrivateMessage("用户 staffId", {
msgtype: "markdown",
title: "通知",
content: "## 通知\n\n请查看最新处理结果。",
});通过 sessionWebhook 发群聊
sessionWebhook 来自钉钉 HTTP 回调消息体,适合在用户 @ 机器人之后回复当前群聊。
await bot.sendGroupMessage(req.body.sessionWebhook, "群聊回复");指定 @ 用户:
await bot.sendGroupMessage(req.body.sessionWebhook, "请关注这条消息", {
atUserIds: ["staffId1"],
});Markdown 群聊:
await bot.sendGroupMessage(req.body.sessionWebhook, {
msgtype: "markdown",
title: "群聊通知",
content: "## 群聊通知\n\n- 已处理完成",
});固定群机器人 Webhook 推送
如果你在群机器人设置里复制到了固定 Webhook:
https://oapi.dingtalk.com/robot/send?access_token=xxx可以使用 sendWebhookMessage 主动推送消息。这个能力适合监控告警、定时日报、定时巡检结果等场景,不需要等用户先私聊或 @ 机器人。
普通文本:
await bot.sendWebhookMessage(
process.env.DINGTALK_WEBHOOK_URL,
"监控告警:订单 API 响应超时"
);Markdown:
await bot.sendWebhookMessage(process.env.DINGTALK_WEBHOOK_URL, {
msgtype: "markdown",
title: "监控告警",
content: [
"## 监控告警",
"",
"- 服务:订单 API",
"- 状态:响应超时",
"- 请及时处理",
].join("\n"),
});@ 指定用户:
await bot.sendWebhookMessage(
process.env.DINGTALK_WEBHOOK_URL,
"请关注这条告警",
{
atUserIds: ["staffId1"],
}
);@ 所有人:
await bot.sendWebhookMessage(
process.env.DINGTALK_WEBHOOK_URL,
"重要告警,请所有人关注",
{
isAtAll: true,
}
);如果开启了关键词安全设置,消息内容必须包含对应关键词,否则会被钉钉拒绝。
自定义机器人加签
如果群机器人安全设置勾选了「加签」,调用 webhook 时必须在 URL 上拼 timestamp 和 sign,本包已内置处理。
构造时传入 webhookSecret,后续所有 sendWebhookMessage 调用都会自动加签:
const bot = createDingTalkBot({
webhookSecret: process.env.DINGTALK_ROBOT_SECRET,
});
await bot.sendWebhookMessage(process.env.DINGTALK_WEBHOOK_URL, "已加签");也可以在单次调用时通过第 4 个参数 secret 覆盖(优先级高于构造时的 webhookSecret):
await bot.sendWebhookMessage(webhookUrl, "临时加签", {}, "SECxxxxxx");如果只想拿到签好的 URL 自己用,可以调用独立函数:
const { signWebhookUrl } = require("dingtalk-chat-bot");
const signed = signWebhookUrl(webhookUrl, "SECxxxxxx");webhookSecret / secret 留空时不加签,方便同一份代码同时兼容启用 / 未启用加签的机器人。
sendGroupMessage走的是钉钉 HTTP 回调里的sessionWebhook(临时地址,自带 token),不需要也不应该加签。
示例消息与文本路由 (dingtalk-chat-bot/examples)
开箱即用的菜单 / Markdown / 时间回复 / 默认路由,免去自己再写一份样板代码。
const {
buildMenu, // → markdown 菜单
buildMarkdownDemo, // → markdown 示例
buildTextDemo, // → 文本示例
buildTimeReply, // → 当前服务器时间
handleUserMessage, // → 默认文本路由
} = require("dingtalk-chat-bot/examples");
await bot.sendWebhookMessage(WEBHOOK_URL, buildMenu());handleUserMessage(text) 把用户文本映射到合适的示例回复,可直接接到 HTTP 回调里:
| 用户发送 | 回复内容 |
| ---------------------------------- | --------------------- |
| 菜单 / help / /help / 帮助 | 菜单 markdown |
| 文本 / text | 文本示例 |
| markdown / md / 示例markdown | Markdown 示例 |
| 时间 / time | 当前服务器时间 |
| 空字符串 | 提示重新发送 |
| 其他 | 回声 + 菜单引导 |
接入示例:
const { handleUserMessage } = require("dingtalk-chat-bot/examples");
app.post("/dingtalk/robot", (req, res) => {
const text = (req.body && req.body.text && req.body.text.content) || "";
res.json(bot.buildReplyPayload(handleUserMessage(text), req.body));
});示例服务
仓库里的 server.js 是一个 Express 示例,不会进入 npm 发布包。你可以本地运行它测试 HTTP 回调:
npm install
cp .env.example .env
npm start默认接口:
POST /dingtalk/robot:同步回复示例。POST /dingtalk/robot-async:先同步确认,再异步发送消息示例。GET /health:健康检查。
发布说明
package.json 的 files 字段只显式包含这些项目文件:
index.jsexamples.jsREADME.md
package.json 会被 npm 自动包含。因此 .env、server.js、package-lock.json、node_modules 都不会进入 npm 包。
