微信机器人接口:REST API vs WebSocket 选型建议

参考资料

一、先搞清楚:这里的 WebSocket 指什么

做微信机器人时,你需要和"机器人API服务"通信。API服务通常提供两种协议选项:

  • REST API(HTTP + Webhook):发消息你主动调 HTTP POST,收消息 API 服务主动 POST 到你的公网回调地址
  • WebSocket:你和 API 服务之间建一条 TCP 长连接,发消息和收消息都在这条连接上双向通信

两种协议解决的是同一个问题(和微信服务器之间通过机器人API服务收发消息),只是通信方式不同。选哪个,取决于你的应用架构和部署条件。

二、REST API 模式详解

通信流程

复制代码
发消息:你的应用 ──HTTP POST──► API服务 ──► 微信服务器
收消息:API服务 ──HTTP POST──► 你的公网回调地址

两个方向用的是两条独立的 HTTP 通道:

方向 方式 触发方
发送消息 你主动调 POST 接口 你的应用
接收消息 API 服务主动 POST 到你配置的回调 URL API 服务

REST API 的代码骨架

以 WTAPI 为例(HTTP + Webhook 形式),接口细节以文档为准(weiti.apifox.cn):

python 复制代码
from flask import Flask, request, jsonify
import requests, queue, threading, time, random

app = Flask(__name__)
msg_queue = queue.Queue()

BASE_URL = "https://wx.chuapi.com"
TOKEN = "你的X-finder-TOKEN"
APP_ID = "你的appId"

# ① 发送消息:主动调 HTTP POST
def send_text(to_wxid, content):
    resp = requests.post(
        f"{BASE_URL}/finder/v2/api/message/postText",
        headers={"Content-Type": "application/json", "X-finder-TOKEN": TOKEN},
        json={"appId": APP_ID, "toWxid": to_wxid, "content": content},
        timeout=10
    )
    return resp.json().get("ret") == 200

# ② 接收消息:被动等 Webhook 回调
@app.route("/callback", methods=["POST"])
def callback():
    msg = request.get_json()
    if msg and msg.get("msgType") == 1:
        msg_queue.put(msg)
    return jsonify({"ret": 200})  # 5秒内必须返回

# ③ 消费者:串行发送 + 限频
def consumer():
    while True:
        msg = msg_queue.get()
        to_wxid = msg.get("chatRoomId") or msg["fromUser"]
        send_text(to_wxid, f"已收到:{msg['content']}")
        time.sleep(random.uniform(1, 5))

threading.Thread(target=consumer, daemon=True).start()

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8080)

REST API 的硬性要求

Webhook 回调需要你的应用有公网可达的 URL。本地开发时用 ngrok 做内网穿透:

bash 复制代码
ngrok http 8080
# 把 https://xxx.ngrok.io/callback 配到 API 服务后台

三、WebSocket 模式详解

通信流程

复制代码
你的应用 ◄──── TCP 长连接 ────► API服务 ──► 微信服务器
(发和收都在同一条连接上)

你只需要向 API 服务发起一次 WebSocket 连接请求,之后:

  • 收消息:API 服务主动往这条连接推送 JSON
  • 发消息:你往这条连接发 JSON 请求

WebSocket 的代码骨架

某些 API 服务提供 WebSocket 接口时,代码长这样:

python 复制代码
import asyncio, json, random
import websockets

WS_URL = "wss://api.example.com/ws?token=你的Token"

async def main():
    async with websockets.connect(WS_URL) as ws:
        # 发送登录指令(假设 WebSocket 模式需要先认证)
        await ws.send(json.dumps({
            "action": "login",
            "appId": "你的appId"
        }))

        # 循环收消息 + 发消息
        while True:
            # ① 接收消息:API 服务主动推过来
            raw = await ws.recv()
            msg = json.loads(raw)

            if msg.get("type") == "message" and msg.get("msgType") == 1:
                to_wxid = msg.get("chatRoomId") or msg["fromUser"]
                content = f"已收到:{msg['content']}"

                # ② 发送消息:往同一条连接发请求
                await ws.send(json.dumps({
                    "action": "postText",
                    "appId": "你的appId",
                    "toWxid": to_wxid,
                    "content": content
                }))

                # 限频
                await asyncio.sleep(random.uniform(1, 5))

asyncio.run(main())

WebSocket 的额外工作

长连接需要处理心跳和断线重连:

python 复制代码
async def heart_beat(ws):
    """每 30 秒发一次心跳"""
    while True:
        await asyncio.sleep(30)
        try:
            await ws.send(json.dumps({"action": "ping"}))
        except:
            break  # 连接断了,交给外层重连

async def connect_with_retry():
    """带指数退避的重连"""
    delay = 1
    while True:
        try:
            async with websockets.connect(WS_URL) as ws:
                await heart_beat(ws)  # 启动心跳
                # ... 正常收发逻辑
                delay = 1  # 连接成功后重置
        except Exception as e:
            print(f"连接断开,{delay}秒后重连: {e}")
            await asyncio.sleep(delay)
            delay = min(delay * 2, 30)  # 指数退避,最多 30 秒

四、两种协议横向对比

对比项 REST API(HTTP + Webhook) WebSocket
部署要求 需要公网回调 URL 只要能出网(不需要公网入站)
网络限制 如果你的服务器在内网,需要内网穿透或公网服务器 内网服务器直接连出去就行
连接管理 无状态,每次请求独立 需要维护长连接、心跳、重连
实时性 Webhook 推送有毫秒级延迟 同一条连接,延迟更低
断线影响 回调断了 API 服务会重推(有重发机制) 连接断了期间的消息可能丢失(取决于服务端实现)
发送限频 靠消费者串行 + 随机间隔控制 同样需要控制,但连接层面可以做流控
防火墙 需要开放入站端口(80/443) 只需要出站权限(几乎所有网络都允许)
多实例 负载均衡分发 Webhook,天然支持水平扩展 每条 WebSocket 连接绑定单个实例,需要连接粘性
代码复杂度 低(HTTP 请求 + Flask/FastAPI) 中(需要 asyncio + 心跳 + 重连)
适用场景 大多数业务场景 内网服务器、出站受限网络、低延迟要求

五、选型决策树

复制代码
你的服务器有公网 IP 吗?
├── 有 → 用 REST API(HTTP + Webhook)
│       理由:部署简单、有重发机制、天然支持多实例
│
└── 没有(内网/VPS 无公网入站)
    ├── 能做内网穿透(ngrok/frp)?
    │   ├── 能 → 还是用 REST API(穿透后就是公网 URL)
    │   └── 不能 → 用 WebSocket
    │
    └── 必须用 WebSocket(出站受限网络/极低延迟要求)

90% 的场景选 REST API。原因:

  1. Webhook 有重发机制:你的回调临时挂了,API 服务会重推消息,不会丢;WebSocket 连接断了期间的消息大概率直接丢
  2. 部署简单:不用管连接管理、心跳、重连,Flask 写个回调接口就行
  3. 水平扩展友好:多实例 + 负载均衡就能抗高并发,WebSocket 需要连接粘性或服务端消息同步

WebSocket 的真正优势在内网服务器场景------服务器不能被外部访问(没有公网 IP、防火墙封了入站),但能主动连出去。这时候 WebSocket 是唯一选择。

六、混合方案

某些场景下两种协议可以配合使用:

复制代码
                    ┌─ WebSocket(实时推送前端管理面板)
你的微信机器人服务 ──┤
                    └─ REST API(和 API 服务交互收发消息)

这里的 WebSocket 不是和机器人 API 服务的通信,而是你自己的应用内部------后端通过 Webhook 收消息后,用 WebSocket 推给前端页面做实时展示。这是两个不同层级的通信,不冲突。

七、小结

微信机器人接口的协议选型:REST API(HTTP + Webhook)是默认选择 ,部署简单、有重发机制、天然支持多实例;WebSocket 适合内网服务器(无公网入站)或极低延迟要求的场景,但需要自己维护心跳和重连。判断标准只有一个:你的服务器能不能被 API 服务访问到(公网可达)? 能就选 REST,不能就选 WebSocket。两种协议的业务逻辑(发消息、处理回调、串行限频)是一样的,换的只是通信层。接口路径和参数以官方文档为准,开发前建议先确认 API 服务提供哪种协议。

相关推荐
极客互动API2 小时前
极客互动-企业微信基于外部API接口实现AI客服自动接管外部联系人消息收发
java·微信·企业微信·ai编程·rpa
别动我齐刘海2 小时前
ROS2 Jazzy + C++ 实战路线——ros2_control
c++·人工智能·python·opencv·机器学习·机器人·github
爱研究的小梁2 小时前
告别实验室理想网络,真实场景下具身智能远程操控怎么干?
网络·人工智能·机器人·信息与通信
深蓝学院3 小时前
六大具身路线详解:模块化、技能编排、IL、RL、VLA、世界模型,到底在“吵”什么。。。
机器人·具身智能·vla·世界模型
明志数科3 小时前
机器人数据采集过程中五类异常片段的判定与处理
机器学习·机器人
随性而行3603 小时前
企业微信二次开发实战:基于企业微信API构建自动化营销触达系统
微信
PascalXie17 小时前
服务机器人避障用的深度相机,主流选型有哪些?
计算机视觉·机器人
鲁邦通物联网18 小时前
机器人梯控防夹避让设计:高峰期人机混行状态机解析
机器人·机器人梯控·agv梯控·机器人乘梯·机器人自主乘梯
倍利福猎头公司官方账号19 小时前
2026具身智能赛道还火热吗?机器人人选该如何思考下半年的工作机会?
人工智能·面试·职场和发展·机器人·求职招聘