微信机器人WebSocket接口怎么使用?
一、WebSocket 在微信机器人里的位置
先明确一点:微信机器人的 API 侧通信协议是 HTTP + Webhook——你发请求用 HTTP,平台推消息给你用 Webhook 回调。WebSocket 不出现在 API 层,而是出现在你自己的应用架构里。
典型场景是:后端通过 Webhook 收到微信消息后,需要实时推给前端页面(比如一个 Web 管理后台或在线客服面板)。如果前端用轮询,每秒请求一次既浪费资源又有延迟;用 WebSocket 建一条长连接,消息到了后端立刻推过去,延迟可以压到毫秒级。
整条链路是这样的:
微信用户发消息
│
▼
平台 Webhook POST ──► 你的后端服务器 ──► WebSocket 推送 ──► 前端页面实时显示
这篇文章讲的就是中间那段:从收到 Webhook 到 WebSocket 推送的实现。
二、技术选型
Node.js + ws 库是最轻量的方案。一个文件搞定 HTTP 服务(接收 Webhook)和 WebSocket 服务(推送前端),不需要引入 Express 或 Koa。
npm init -y
npm install ws
三、服务端实现
核心逻辑:起一个 HTTP 服务接收 Webhook 回调,同时把同一个端口升级为 WebSocket 服务供前端连接。收到微信消息后,广播给所有已连接的前端客户端。
const { WebSocketServer } = require("ws");
const http = require("http");
// 存储所有前端连接
const clients = new Set();
// HTTP 服务:接收 Webhook 回调
const server = http.createServer((req, res) => {
if (req.method === "POST" && req.url === "/callback") {
let body = "";
req.on("data", (chunk) => (body += chunk));
req.on("end", () => {
try {
const msg = JSON.parse(body);
// 组装推给前端的数据
const pushData = {
appId: msg.appId,
msgType: msg.msgType,
fromUser: msg.fromUser,
nickName: msg.nickName,
content: msg.content,
chatRoomId: msg.chatRoomId || "",
createTime: msg.createTime,
// 标记是私聊还是群聊
chatType: msg.chatRoomId ? "group" : "private",
};
// 广播给所有连接的前端
const payload = JSON.stringify(pushData);
for (const client of clients) {
if (client.readyState === 1) {
// 1 = OPEN
client.send(payload);
}
}
console.log(`收到消息来自 ${msg.nickName},已推送给 ${clients.size} 个客户端`);
} catch (e) {
console.error("解析失败:", e.message);
}
// 必须返回 {"ret": 200},否则平台会重推
res.writeHead(200, { "Content-Type": "application/json" });
res.end('{"ret": 200}');
});
} else {
res.writeHead(404);
res.end();
}
});
// WebSocket 服务:前端连接进来
const wss = new WebSocketServer({ server, path: "/ws" });
wss.on("connection", (ws, req) => {
clients.add(ws);
console.log(`前端已连接,当前在线 ${clients.size} 个`);
// 发送一条欢迎消息
ws.send(JSON.stringify({ type: "connected", msg: "WebSocket 已连接" }));
ws.on("message", (data) => {
// 前端发来的消息,可以做心跳处理
const text = data.toString();
if (text === "ping") {
ws.send("pong"); // 心跳响应
}
});
ws.on("close", () => {
clients.delete(ws);
console.log(`前端断开,当前在线 ${clients.size} 个`);
});
ws.on("error", () => {
clients.delete(ws);
});
});
server.listen(8080, () => {
console.log("服务启动: HTTP回调 http://localhost:8080/callback");
console.log(" WebSocket ws://localhost:8080/ws");
});
四、前端连接实现
前端浏览器原生支持 WebSocket,不需要额外库:
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>消息实时面板</title></head>
<body>
<div id="messages" style="max-height: 500px; overflow-y: auto;"></div>
<script>
const ws = new WebSocket("ws://localhost:8080/ws");
// 连接成功
ws.onopen = () => {
document.getElementById("messages").innerHTML +=
"<p style='color:green'>已连接</p>";
// 启动心跳,每 30 秒发一次
setInterval(() => {
if (ws.readyState === WebSocket.OPEN) ws.send("ping");
}, 30000);
};
// 收到消息
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
const div = document.getElementById("messages");
const time = new Date().toLocaleTimeString();
const typeLabel = data.chatType === "group" ? "[群聊]" : "[私聊]";
div.innerHTML +=
`<p>${time} ${typeLabel} <b>${data.nickName || data.fromUser}</b>: ${data.content}</p>`;
div.scrollTop = div.scrollHeight; // 自动滚到底
};
// 连接断开
ws.onclose = () => {
document.getElementById("messages").innerHTML +=
"<p style='color:red'>连接断开,5秒后重连</p>";
setTimeout(() => location.reload(), 5000);
};
ws.onerror = () => {
console.error("WebSocket 错误");
};
</script>
</body>
</html>
五、心跳与断线重连
WebSocket 长连接最大的问题是:网络波动、服务重启后连接会断掉。上面前端代码里已经有了一个简单的重连(刷新页面),但生产环境需要更健壮的方案:
后端心跳检测
// 每 60 秒检查一次所有连接
setInterval(() => {
for (const client of clients) {
if (client.readyState === 1) {
// 发 ping,如果客户端没回 pong 说明连接已死
client.ping();
} else {
clients.delete(client);
}
}
}, 60000);
前端指数退避重连
let reconnectCount = 0;
function connect() {
const ws = new WebSocket("ws://localhost:8080/ws");
ws.onopen = () => {
reconnectCount = 0; // 重置计数
console.log("已连接");
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log("收到:", data);
};
ws.onclose = () => {
reconnectCount++;
// 1秒、2秒、4秒、8秒...最多 30 秒
const delay = Math.min(1000 * Math.pow(2, reconnectCount), 30000);
console.log(`${delay / 1000}秒后重连`);
setTimeout(connect, delay);
};
}
connect();
六、消息格式设计
推给前端的数据结构建议统一格式,方便前端解析:
{
"appId": "应用ID",
"msgType": 1,
"fromUser": "wxid_abc123",
"nickName": "张三",
"content": "你好",
"chatRoomId": "",
"chatType": "private",
"createTime": 1697000000
}
msgType 的常见值:
| msgType | 含义 |
|---|---|
| 1 | 文本消息 |
| 3 | 图片消息 |
| 49 | 链接/卡片消息 |
前端根据 msgType 渲染不同的展示样式。
七、生产部署的几个要点
1. Nginx 反向代理 WebSocket
WebSocket 走 HTTP 升级协议,Nginx 配置需要加 Upgrade 头:
location /ws {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400; # 长连接超时设长
}
2. 多实例广播
如果后端起了多个进程(比如用 PM2 cluster 模式),一个 Webhook 进程收到的消息需要广播到其他进程的 WebSocket 客户端。用 Redis Pub/Sub 做进程间通信:
const redis = require("redis");
const sub = redis.createClient();
const pub = redis.createClient();
// 收到 Webhook 后发布到 Redis
sub.subscribe("wx_messages");
sub.on("message", (channel, message) => {
for (const client of clients) {
if (client.readyState === 1) client.send(message);
}
});
// Webhook 收到消息时
function onWebhookReceived(msg) {
pub.publish("wx_messages", JSON.stringify(msg));
}
3. 连接数控制
单个 Node.js 进程的 WebSocket 连接数建议控制在 5000 以内,超过的话用多个实例 + 负载均衡。
八、WebSocket vs 轮询 vs SSE 对比
| 方案 | 实时性 | 服务器开销 | 实现复杂度 | 双向通信 |
|---|---|---|---|---|
| 前端轮询 | 低(1-5秒延迟) | 高(大量无效请求) | 最低 | 否 |
| SSE | 高 | 中 | 低 | 否(只能服务端→前端) |
| WebSocket | 最高 | 低(一条连接) | 中 | 是 |
如果你的前端只需要看消息不需要发,SSE 也够用;如果前端还要通过同一条连接发送指令(比如"暂停接收"、“切换会话”),WebSocket 更合适。
九、小结
微信机器人的消息实时推送方案里,Webhook 负责收、WebSocket 负责推,两者配合构成了完整的实时链路。WebSocket 不碰 API 层,纯粹是你应用内部的实时通信通道。代码量不大,核心就是 HTTP 服务 + WebSocket 服务 + 广播逻辑。把心跳和重连做好,就能稳定跑在生产环境。
参考资料
接口定义与文档参数说明:weiti.apifox.cn
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)