上一篇讲了鉴权,这篇进入正题:消息收发。这是个人微信 API 最核心的能力,也是用得最多的场景。

我做过几个实际项目,都是围绕消息收发展开的:电商订单自动推送给客户、客服机器人自动回复、社群通知定时发送。每个场景用到的消息类型不一样,踩坑点也不同。这篇把常用的几种消息类型梳理一遍,给出完整的代码示例和踩坑记录,建议先跑通再写代码。

一、消息类型有哪些,分别用在什么场景

先理清消息类型和对应的业务场景:

消息类型

典型场景

文本

订单通知、自动回复、群发通知

图片

商品图、活动海报、截图反馈

文件

电子发票、合同、报表

视频

产品介绍、操作教程

语音

语音客服、提醒通知

小程序

商品卡片、活动页面

链接

文章分享、商品链接

不同类型的参数和限制都不一样,下面挨个讲。

二、消息发送

1. 文本消息

最基础的类型,电商订单通知、机器人自动回复都用它:

def send_text(self, w_id, wc_id, content):
    return self._post("/sendText", {
        "wId": w_id, "wcId": wc_id, "content": content
    })

坑点:

  • content 不能超过 500 字,超了被截断

  • 别包含敏感词(秒杀、返利等),否则发不出去

  • @群成员要用特殊格式,不是直接写 @昵称

文档:发送文本消息

2. 图片消息

电商场景经常要发商品图、活动海报:

def send_image(self, w_id, wc_id, image_url):
    return self._post("/sendImage", {
        "wId": w_id, "wcId": wc_id, "content": image_url
    })

坑点:

  • 必须 JPG/PNG,不支持 BMP

  • 不超过 5MB

  • URL 必须公网可访问,内网地址会报错

  • 建议用 CDN,避免服务器带宽影响加载

文档:发送图片消息

3. 文件消息

发电子发票、合同、报表:

def send_file(self, w_id, wc_id, file_url, file_name):
    return self._post("/sendFile", {
        "wId": w_id, "wcId": wc_id,
        "content": file_url, "fileName": file_name
    })

坑点:

  • 支持 PDF、Word、Excel、ZIP 等常见格式

  • 不超过 50MB

  • 文件 URL 默认 24 小时有效,定时任务要重新生成

  • 大文件超时至少 15 秒

文档:发送文件消息

4. 视频消息

产品介绍、操作教程:

def send_video(self, w_id, wc_id, video_url):
    return self._post("/sendVideo", {
        "wId": w_id, "wcId": wc_id, "content": video_url
    })

文档:发送视频消息

5. 小程序消息

电商场景特别有用,直接发商品卡片:

def send_applet(self, w_id, wc_id, app_id, page, title, desc, img_url):
    return self._post("/sendApplets", {
        "wId": w_id, "wcId": wc_id,
        "appId": app_id, "pagePath": page,
        "title": title, "description": desc, "imageUrl": img_url
    })

文档:发送小程序消息

三、消息接收(Webhook)

机器人要自动回复,必须能收消息。收消息靠 Webhook,不能主动拉取。流程:在平台后台配一个回调地址,微信收到新消息后,平台 POST 到你的地址。

1. 设置回调

def set_callback(self, w_id, callback_url):
    return self._post("/setCallback", {"wId": w_id, "url": callback_url})

文档:设置 HTTP 回调地址

2. 客服机器人示例(Flask)

一个简单的电商客服机器人,收到消息自动回复:

from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route("/webhook", methods=["POST"])
def webhook():
    data = request.json
    msg_type = data.get("messageType")
    from_user = data.get("fromUser")
    content = data.get("content", "")
    
    if msg_type == 1:  # 文本消息
        reply = generate_reply(content)
        if reply:
            client.send_text(w_id, from_user, reply)
    
    return jsonify({"code": "1000", "message": "success"})

def generate_reply(content):
    """简单的关键词匹配回复"""
    if "发货" in content:
        return "您的订单已发出,请耐心等待"
    elif "退款" in content:
        return "退款申请已收到,客服将在24小时内处理"
    elif "价格" in content:
        return "商品价格请点击小程序卡片查看"
    return None  # 无法识别的,转人工

完整的事件类型见 Webhook 事件索引回调字典

3. 下载消息中的资源

客户发的图片、文件不能直接用 URL 访问,要调下载接口:

def download_file(self, w_id, msg_id, aes_key, file_id):
    return self._post("/downloadFile", {
        "wId": w_id, "msgId": msg_id,
        "aesKey": aes_key, "fileId": file_id
    })

文档:下载文件下载图片下载语音

四、消息转发

平台支持转发已收到的消息,不用重新上传资源:

客服转接场景特别有用:客户发给 A 客服的消息,转给 B 客服处理,不用重新上传。

五、实战:电商订单全流程通知

把上面的能力组合起来,做一个电商订单通知系统:

class OrderNotifier:
    def __init__(self, client, w_id):
        self.client = client
        self.w_id = w_id
    
    def notify_order_placed(self, customer_wxid, order):
        """下单通知"""
        msg = f"订单已创建\n订单号:{order['id']}\n金额:¥{order['amount']}\n商品:{order['items']}"
        self.client.send_text(self.w_id, customer_wxid, msg)
    
    def notify_order_paid(self, customer_wxid, order):
        """付款通知"""
        msg = f"支付成功\n订单号:{order['id']}\n我们将在24小时内发货"
        self.client.send_text(self.w_id, customer_wxid, msg)
    
    def notify_order_shipped(self, customer_wxid, order):
        """发货通知"""
        msg = f"已发货\n订单号:{order['id']}\n物流:{order['tracking_no']}"
        self.client.send_text(self.w_id, customer_wxid, msg)
        # 发物流截图
        if order.get('tracking_image'):
            self.client.send_image(self.w_id, customer_wxid, order['tracking_image'])
    
    def notify_order_completed(self, customer_wxid, order):
        """签收通知"""
        msg = f"订单已完成\n订单号:{order['id']}\n感谢您的购买,欢迎再来!"
        self.client.send_text(self.w_id, customer_wxid, msg)
        # 发优惠券小程序
        self.client.send_applet(
            self.w_id, customer_wxid,
            app_id="wx_coupon_appid",
            page="pages/coupon/index",
            title="领取优惠券",
            desc="感谢购买,送您一张优惠券",
            img_url=order['coupon_image']
        )

六、踩坑记录

坑1:消息重复发送

调用返回超时,我以为没发出去又调了一次,客户收到两条。后来用 newMsgId 做去重,5 分钟内同一 newMsgId 只处理一次。

坑2:图片 URL 不可达

用了公司内网的图片地址,接口返回成功但对方收不到图。平台服务器访问不到内网,换公网 CDN 后正常。

坑3:语音格式不支持

客户发了 MP3 语音,接收端播放不了。微信语音用 silk 或 amr 格式,MP3 要用 silk-v3-decoder 转换。语音的 length 参数要用 voicelength 回调字段的真实值,不能瞎填。

坑4:机器人回复太快被风控

客服机器人秒回,一天回复 500 条,号被限流了。后来加了 3-6 秒随机延迟,模拟人工回复节奏,再没出问题。

七、小结

消息收发是微信 API 的核心,文本相对简单,图片和文件要注意 URL 可达性和格式限制。Webhook 接收必须做幂等和异步处理,否则容易丢消息或重复处理。

电商、客服机器人、社群运营这些场景,核心都是消息收发。把这套能力封装好,后面做啥业务都顺手。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐