
在小程序的实际运营中,用户完成下单后,往往希望实时了解订单的处理进度,例如“已支付”“备货中”“已发货”“已完成”等状态变化。传统的做法是让用户主动进入小程序、点击“我的订单”页面来查看。这种方式虽然可行,但存在两个明显不足:一是用户需要主动操作,体验不够流畅;二是当订单状态发生变化时,用户无法第一时间获知,容易产生焦虑或反复咨询客服。
为了解决这个问题,开发者可以利用小程序提供的“客服消息”能力,在订单状态发生变化时,主动向用户发送一条消息提醒。这种消息会出现在微信的“客服会话”列表中,用户点击后可以进入小程序查看详情,也可以直接回复消息与客服互动。
需要注意的是,客服消息并非可以随意发送。它有两个重要前提:第一,用户必须在最近 48 小时内曾向小程序的客服会话发送过消息(即触发过一次客服会话);第二,每次用户消息可以回复最多 5 条客服消息。这意味着,我们不能在用户从未互动的情况下主动推送任何消息。因此,在设计订单状态推送方案时,需要引导用户在下单前或下单后主动发起一次客服咨询,或者利用用户已有的客服会话记录来发送后续的状态更新。
在开始编写代码之前,需要完成以下几项基础配置工作。
登录小程序管理后台,在左侧菜单中找到“功能”->“客服”。确保已经开通了客服消息功能。开通后,系统会自动分配一个客服账号,你也可以添加多名客服人员,并设置在线/离线状态。这一步通常在创建小程序时就已经完成,如果没有开通,按照页面提示操作即可。
在小程序管理后台的“开发”->“开发管理”->“开发设置”中,可以看到小程序的 AppID。AppSecret 需要点击“重置”或“生成”来获取,首次获取时会显示在页面上,请务必保存好。如果遗失,只能重置。AppSecret 用于调用微信接口时获取 access_token,非常重要,不能泄露在前端代码中。
如果你的订单状态变更逻辑发生在自己的后端服务器上(通常如此),需要在“开发”->“开发设置”->“服务器域名”中,配置“request 合法域名”为你后端 API 所在的域名。否则,小程序前端无法调用你后端的接口。
客服消息的推送需要通过微信的 HTTP API 来完成,基本流程如下:
后端服务器使用 AppID 和 AppSecret 换取 access_token(有效期通常为 2 小时,需要缓存并定时刷新)。
当订单状态发生变化时,后端根据用户的 openId,调用客服消息接口发送文本、图片或链接消息。
微信服务器收到请求后,将消息推送到用户的客服会话中。
后端的编程语言不限,这里以通用的思路来描述实现步骤,你可以根据自己熟悉的技术栈(例如 Python、Node.js、Java、PHP 等)进行编码。
access_token 是调用绝大多数微信接口的凭证。由于每个小程序每天获取 access_token 的次数有限(目前是 2000 次),并且每个 token 有效期为 7200 秒,因此不能每次发送消息都去获取一次,而应该将 token 缓存起来,在过期前重复使用。
实现逻辑如下:
首先检查缓存中是否存在有效的 access_token。可以将其存储在内存、文件或 Redis 中,记录下获取时间。
如果不存在或已过期,则调用接口 GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=你的APPID&secret=你的SECRET。
接口返回的数据中包含 access_token 和 expires_in(有效秒数)。将 token 保存下来,并记录当前时间戳。
下次调用时,判断当前时间是否小于“获取时间 + expires_in - 200 秒”(预留 200 秒安全边界),如果有效则直接使用缓存中的 token。
微信客服消息接口的地址为:POST https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
请求体为 JSON 格式,至少需要包含两个字段:touser(用户的 openId)和 msgtype(消息类型)。对于订单状态推送,通常使用文本消息(text)或链接消息(link)。
文本消息示例:
{
"touser": "用户openId",
"msgtype": "text",
"text": {
"content": "您的订单已发货,运单号:SF1234567890。点击进入小程序查看详情。"
}}链接消息示例:
{
"touser": "用户openId",
"msgtype": "link",
"link": {
"title": "订单状态更新",
"description": "您的订单已发货,点击查看物流信息",
"url": "https://yourdomain.com/order/detail?orderId=123",
"thumb_url": "https://yourdomain.com/thumb.jpg"
}}需要注意的是,链接消息中的 url 必须是已经配置到业务域名中的网址。如果希望用户点击后直接跳转到小程序内的某个页面,可以使用小程序卡片消息(miniprogrampage 类型),这种消息会直接打开小程序。
小程序卡片消息示例:
{
"touser": "用户openId",
"msgtype": "miniprogrampage",
"miniprogrampage": {
"title": "订单状态更新",
"pagepath": "pages/order/detail?orderId=123",
"thumb_media_id": "图片素材的media_id"
}}使用小程序卡片消息时,需要先通过素材管理接口上传一张图片(建议尺寸 520*416),获得 thumb_media_id。
通常,订单状态的变化发生在以下几种场景:
用户支付成功后(支付回调通知)
商家后台修改订单状态(发货、完成、取消等)
定时任务检查超时未支付自动取消
在这些业务逻辑处理完成后,判断该订单对应的用户是否满足客服消息发送条件。最简单的判断方式是:调用发送接口,如果微信返回错误码 45065(表示用户未在 48 小时内给客服发消息),则本次推送失败,可以记录下来稍后重试或放弃。更优雅的做法是在订单表中增加一个字段 last_customer_msg_time,记录用户最后一次向客服发消息的时间戳,只有当前时间距离该时间戳小于 48 小时才尝试发送。
由于客服消息的前提是用户必须先向客服会话发送过消息,因此前端需要设计一个合理的引导机制,确保大部分用户在订单生命周期内已经触发过客服会话。
在小程序的页面中,可以使用 来创建一个客服按钮。用户点击后,会直接打开客服会话界面,并且系统会自动发送一条“用户进入客服会话”的事件。这条事件会被视为用户发送了一条消息,从而满足后续 48 小时内可回复的条件。
建议在以下位置放置客服按钮:
订单详情页底部:方便用户在下单后对订单有疑问时直接咨询。
个人中心页面:作为常用的联系方式入口。
购物车页面或结算页面:用户在下单前可能咨询商品问题。
按钮的样式可以根据小程序的设计风格自定义,代码示例:
在 handleContact 回调中,可以记录用户点击客服按钮的时间,并更新到后端用户表中,用于判断后续是否可以发送客服消息。
需要注意的是,仅仅点击客服按钮打开会话窗口,用户如果没有输入任何文字并发送,是否算作“发送了一条消息”?经过验证,当用户通过 open-type="contact" 打开客服会话时,微信会自动发送一条“进入会话”的系统消息,这条消息会被计入用户的消息记录,因此开发者可以据此在 48 小时内回复用户。但为了稳妥起见,最好引导用户发送一条真实的消息,例如在客服会话的自动回复中加入“回复 1 接收订单状态提醒”之类的提示。
有些开发者可能会想,能否在小程序启动时自动触发客服会话,从而让每个用户都满足接收消息的条件?答案是不可以。open-type="contact" 的按钮必须由用户主动点击才能触发,微信小程序的安全机制禁止任何形式的自动弹出客服会话。因此,只能通过合理的 UI 设计提高用户主动点击的比例。
假设一个典型的电商小程序订单流程,我们来串一下整个客服消息推送的流程。
用户进入小程序,浏览商品后,在结算页面看到“有问题?联系客服”的按钮。用户点击按钮,打开了客服会话,询问“这个商品什么时候发货?”客服人员(或者自动回复)回复了“一般 24 小时内发货”。此时,用户的 openId 和本次客服会话被记录下来,有效时间 48 小时。
用户提交订单并完成支付。支付成功后,微信支付会异步通知你的后端服务器。后端在处理支付回调时,会调用“发送客服消息”接口,向该用户的 openId 发送一条文本消息:“您的订单已支付成功,我们会尽快为您发货。”
商家后台操作发货,录入物流单号。后端在更新订单状态为“已发货”时,再次调用客服消息接口,发送一条小程序卡片消息:“您的订单已发货,点击查看物流轨迹。”用户点击卡片后,直接进入小程序的物流详情页。
用户确认收货后(或者系统自动确认),订单状态变为“已完成”。后端发送一条感谢消息:“感谢您的购买,欢迎下次光临。有任何问题可以随时联系我们。”
如果用户超过 48 小时没有再次点击客服按钮,后续的消息将无法发送。这时可以在用户再次打开小程序时,弹出一个提示:“为了及时接收订单状态通知,请点击联系客服按钮激活消息提醒。”
微信对客服消息的发送频率有一定的限制。对于同一个用户,每个客服账号每小时最多可以发送 200 条消息,每天最多 2000 条。对于大多数小程序来说,这个限制是足够的。但如果有大量订单集中推送,需要注意控制频率,可以引入消息队列进行削峰填谷。
客服消息的内容必须符合微信的相关规范,不能包含诱导分享、虚假宣传、违法信息等。订单状态推送属于正常的服务通知,一般没有问题。但如果消息中包含了外部链接,需要注意链接域名的安全性和合规性。
调用客服消息接口时,可能返回各种错误码,需要在代码中做好处理:
0:成功
40001:access_token 无效,需要重新获取
45065:用户未在 48 小时内向客服发消息,本次无法推送
45047:回复条数超过 5 条上限(指针对用户单条消息的回复次数)
45015:回复时间超过 48 小时
对于 45065 错误,可以记录下该用户的订单,下次用户再次点击客服按钮时,补发之前遗漏的状态更新。
如果小程序使用了多个客服账号(例如企业微信中的多人客服),使用客服消息接口发送时,消息会随机分配给一个在线客服。如果想要消息由特定客服发送,需要配合客服管理接口实现,一般情况下默认行为即可满足需求。
可能有人会问:为什么不用模板消息(现称为“一次性订阅消息”)来推送订单状态?模板消息确实更适合订单状态通知,因为它不需要用户先发消息,只需要用户订阅一次即可。但模板消息有以下限制:每条消息都需要用户单独订阅,且订阅后只能发送一次。而客服消息的优势在于,用户只要触发过一次客服会话,后续 48 小时内可以发送多条消息(最多 5 条针对用户每条消息的回复,但实际策略是用户每发一条,可回复 5 条,因此如果用户不说话,则只能发送有限条)。两种方式可以结合使用:对于重要状态变化使用订阅消息,对于辅助性提醒使用客服消息。
如果你希望摆脱“用户必须先发消息”的限制,可以考虑另一个方案:使用手机号快速验证组件或用户信息授权来获取用户的联系方式,然后通过短信或公众号模板消息发送通知。但那是另一种实现路径了。
在客服消息的基础上,还可以做更多事情,例如:
当用户发送“物流”两个字时,自动回复最新的物流信息。
当用户发送“优惠券”时,自动发放一张优惠券并告知使用方式。
结合小程序的 WebSocket 能力,实现客服与用户的实时聊天。
给小程序添加“客服消息”推送订单状态,是一个低成本、高用户体验的功能。它的核心在于理解微信客服消息的触发机制——用户主动发起会话是前提。通过合理的前端引导(放置客服按钮)和后端实现(获取 token、调用发送接口),可以在订单支付成功、发货、完成等关键时刻及时通知用户,减少用户的焦虑和反复查询。
实现时需要注意几点:一是 access_token 必须缓存以避免频繁获取;二是处理各种错误码,特别是 45065 这种情况;三是控制发送频率,避免超过限制。最后,如果用户量大且订单频繁,建议将发送任务放入消息队列中异步处理,避免阻塞主业务逻辑。