Node 微信机器人开发教程:Express 接入收发怎么做
Node 适合做微信机器人网关:回调是 HTTP,发送也是 HTTP,事件驱动和队列都顺手。个人号没有官方 Node SDK 时,自己包一层 client 即可。这篇用 Express 给出可落地的接入方式。
结构
src/
channel.js // 登录状态、发文本
webhook.js // Express 路由
bot.js // 规则
store.js // 去重与会话
worker.js // 消费队列
用 TypeScript 更好,但教程用普通 JS,方便复制。生产建议把 event 类型写死,避免 msg.xxx 满天飞。
Webhook:读原始 body
验签如果按原始字节计算,必须在 express.json() 之前保留 raw。常见写法:
app.use('/hooks/wechat/message', express.raw({ type: '*/*' }));
app.post('/hooks/wechat/message', async (req, res) => {
const token = req.get('x-token');
if (token !== process.env.CALLBACK_TOKEN) {
return res.status(401).end();
}
const raw = req.body.toString('utf8');
const event = parseEvent(raw);
if (!event || store.seen(event.accountId, event.msgId)) {
return res.status(200).json({ ok: true });
}
await store.saveRaw(event.accountId, event.msgId, raw);
await queue.add(event);
return res.status(200).json({ ok: true });
});
立刻 200。queue.add 用 BullMQ / Redis,单机 demo 可以用内存数组,进程一重启会丢,只适合本地。
发送封装
async function sendText({ accountId, to, text, requestId }) {
const online = await channel.isOnline(accountId);
if (!online) {
return { ok: false, code: 'offline' };
}
const resp = await fetch(`${process.env.CHANNEL_BASE_URL}/message/text`, {
method: 'POST',
headers: {
'content-type': 'application/json',
authorization: `Bearer ${process.env.CHANNEL_TOKEN}`,
},
body: JSON.stringify({ accountId, to, content: text, requestId }),
});
const data = await resp.json().catch(() => ({}));
return { ok: resp.ok, status: resp.status, data };
}
URL 为示意。错误码要映射成你们自己的:offline、not_friend、rate_limit、bad_params。业务层不要只拿到 false。
规则与会话锁
function reply(event, session) {
if (session.humanTaken) return null;
if (event.isGroup) return null;
const text = (event.text || '').trim();
if (text === '人工') {
session.takeHuman();
return '已转接,请稍候';
}
if (text.includes('营业时间')) {
return '每天 10:00–21:00,以门店当日安排为准';
}
return '回复「营业时间」或「人工」';
}
Node 里特别容易把会话存在内存 Map 里。多进程 / 多副本会串。会话和去重从第一天就进 Redis 或数据库。
Worker
async function handle(event) {
const session = await store.getSession(event.accountId, event.from);
const text = reply(event, session);
if (!text) return;
await sendText({
accountId: event.accountId,
to: event.from,
text,
requestId: `out-${event.msgId}`,
});
}
同一好友的出站用队列按 key 串行(例如 BullMQ jobId + group),比在代码里 setTimeout 可靠。Serverless(云函数)尤其不要 sleep 频控,函数一结就没了。
本地开发注意
-
回调要公网 HTTPS。本地用内网穿透,域名固定,不要每次换 URL 还去通道后台改
-
Node 默认不要把未捕获异常吞掉,worker 里
try/catch并打 msgid -
fetch记得设超时(AbortController),通道卡住时不要占满事件循环
联调顺序:在线 → 打 webhook → 去重 → 发出文本 → 点“人工”后不再回。
小结
Node 微信机器人开发的关键,是 raw 回调、快速应答、Redis 会话、按账号串行发送。Express 只是入口。先把私聊文本和转人工做稳,图片与群消息作为事件类型扩展,而不是另起一个服务。通道字段以实际对接文档为准,Node 侧用一层 client 隔开即可。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)