ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

微信小程序订阅消息开发全解:一次性与长期订阅实战指南

微信小程序订阅消息开发全解:一次性与长期订阅实战指南 微信小程序的订阅消息几乎是每个做小程序的人都会碰到的模块。不管是外卖的出餐提醒、预约挂号的结果通知还是商城里的发货提醒、活动开奖通知都绕不开“什么时候让用户点订阅”“后端什么时候能把消息真正推出去”这两个问题。这篇文章围绕标题里的两个核心方向展开一次性订阅和长期订阅。我会把开发中容易踩的坑、需要提前想清楚的设计点以及后端发送链路上的关键参数全部展开讲清楚。如果你正在做小程序或者打算给已有项目加消息触达能力这篇内容可以帮你省下不少摸索时间。1. 先分清一次性订阅和长期订阅别选错方向订阅消息最容易被误解的地方就是很多人以为“用户授权一次以后就能随便发”。真实情况远没有这么美好。微信从模板消息改版成订阅消息之后核心逻辑变成了“用户授权次数决定你可以发几条”。一次性订阅和长期订阅在授权方式、可用范围上有本质区别搞混了轻则消息发不出去重则整个消息方案要推倒重来。1.1 一次性订阅用户点一次允许你只拿到一条下发机会一次性订阅是这个功能最基础的形态。用户每点击一次“允许”开发者就获得一次向该用户发送订阅消息的机会。这里的关键词是“一次”。你可以把这个理解成一张一次性餐券用完就没有了。就算用户在同一个页面上点了三次允许你也只是拿到了三条下发额度发一条少一条而不是“永远可以发”。实际开发中很容易出现这样的场景用户下单后点了订阅商家发货时你推送一条提醒用户点进去看到消息了。过两天你希望再推一条“请及时确认收货”的消息发现推送失败返回码 43101。原因很简单订阅额度已经被上一次发货通知消耗掉了。所以一次性订阅只适合做低频、单次强相关的结果通知比如“审核结果已出”“快递已签收”“预约成功”。还有一点要注意用户授权的一次性订阅额度并不是永久保留的超过一定时间没下发会自动失效。所以拿到授权后要尽快规划发送时机不要囤额度。这也是很多项目在“订阅后第二周才推送”时会莫名失败的原因之一。1.2 长期订阅一次授权多次下发但行业门槛不低长期订阅是在一次性订阅基础上推出的进阶能力核心价值是“用户授权一次开发者可以在后续一段时间内多次推送”。看起来解决了所有触达痛点但它有一个非常硬的门槛目前长期订阅只对政务民生、医疗、交通、金融、教育等公共服务属性明显的类目开放。个人主体小程序基本不用想普通电商、工具类小程序也大概率没有长期订阅的入口。这一点我在不少技术群里见过有人反复问“为什么我在后台找不到长期订阅模板”答案往往不是操作问题而是主体类目不在白名单里。如果你的类目真的符合要求在小程序管理后台的“订阅消息”页面新增模板时会看到长期订阅模板的选项。如果看不到说明当前主体或类目暂未开放。长期订阅的模板和一次性订阅在发送接口调用上没有本质区别依然是调用订阅消息发送接口只是授权次数和业务含义不同。这就引出一个实践上的坑后台模板列表里既有一次性模板也有长期模板时一定要在业务代码里做好区分否则很容易出现“用户明明订阅过但发送时依然失败”的情况。1.3 两种订阅的使用场景对比对比维度一次性订阅长期订阅授权行为每次发送前需用户点击允许用户一次授权后续可多次发送下发次数授权一次只能发一条一次授权可获得多个下发次数开放范围所有已认证小程序仅公共服务类目有白名单限制适用场景订单结果、审核通知、核销通知政策变更、账单提醒、周期报告后端设计关注剩余额度用完再引导订阅关注防打扰避免次数被一次刷完简单总结就是能用一次性订阅解决的不要硬上长期订阅能用长期订阅的类目也别把一次性订阅做得太复杂。方案选型不是越高级越好而是越匹配业务越好。2. 前端订阅触发设计弹窗时机和授权率直接挂钩选好订阅类型之后下一个问题就是“怎么让用户愿意点允许”。订阅消息的授权弹窗不是想弹就能弹的微信对调用时机有明确要求必须由用户的点击行为直接触发。你在onLoad里弹、在定时器里弹、在网络回调里弹都会导致弹窗失败或者授权率断崖式下降。2.1 弹出时机把订阅按钮嵌入真实操作流程我是这样做的把订阅动作自然融入用户原本就要做的操作里单独搞一个“开启通知”的入口页面效果一定不好。比如用户在下单后点击“提交订单”支付成功的回调里弹订阅请求用户当时的心态是“我要完成交易”顺手点允许的意愿会高很多。如果搞一个“设置页”让用户主动来开通知绝大多数人根本不会点进来。代码层面直接调用wx.requestSubscribeMessage就行。模板 ID 可以传一个数组但同时弹多个授权框的体验很差我实际测试下来的授权转化率会跌到单独弹窗的一半以下。建议一次只弹一个最核心的模板其他通知通过合并文案处理。Page({ handleOrderSuccess() { // 用户完成支付后进入这个回调此时弹订阅授权 wx.requestSubscribeMessage({ tmplIds: [模板ID例如模板消息 id 的字符串], success(res) { // res 会返回一个对象key 是模板IDvalue 是 accept/reject/ban if (res[模板ID] accept) { // 授权成功把状态上报给后端由后端发送订阅消息 } else { // 用户拒绝记录日志但不要反复强弹 } }, fail(err) { console.error(订阅消息调用失败, err) } }) } })如果你用的是 uniapp写法几乎一致把wx换成uniuni.requestSubscribeMessage的参数和回调结构跟微信原生 API 是同一套迁移成本很低。2.2 授权结果要认真处理别只弹不管wx.requestSubscribeMessage返回的res里value 有三种可能accept表示用户接受了reject表示用户拒绝了ban表示用户已经被系统判定为过度打扰后续不会再弹窗。ban这个状态最容易被忽略一旦出现了短期内再怎么调接口都不会有弹窗需要等一段时间或者引导用户去小程序设置页手动打开通知权限。正确的做法是拿到accept后把状态同步给后端后端记录该用户当前有一个可用的订阅额度拿到reject后不要马上下一次再弹可以等业务节点比如用户再次进入订单详情页时通过一个“开启发货通知”的按钮来二次引导拿到ban就要把入口弱化只保留设置页的开启路径别再骚扰用户。2.3 按钮文案和页面说明影响授权率我对比过两种写法。一种是一句话不说直接弹系统授权框另一种是先在页面里放一个小提示条写着“订阅后可以收到审核结果通知每周最多提醒一次”然后再引导用户点击按钮触发弹窗。后一种的授权率高出不少。原因也简单用户不知道订阅之后会收到什么、多久收一次自然不敢点。你把这两个信息提前告诉用户他心里的确定性上来了授权意愿自然就高了。注意引导文案别写“永久免费通知”“无限次提醒”这类字眼一方面跟实际能力不符另一方面容易被微信判定为误导用户。文案合规这件事出问题比想象中要严重。3. 后端发送链路从 access_token 到订阅消息接口前端拿到了用户授权后端才能真正把消息推出去。这个过程里最核心的是两件事拿到一个有效的access_token然后按接口规范组装参数发起请求。很多第一次做订阅消息的人会在这一步卡很久。3.1 稳定获取 access_token服务端要调用微信接口第一步是拿 AppID 和 AppSecret 换access_token。接口地址是GET https://api.weixin.qq.com/cgi-bin/token?grant_typeclient_credentialappidAPPIDsecretAPPSECRETaccess_token的有效期是 7200 秒两小时而且微信对获取频率有限制。所以强烈建议在服务端做缓存用一个全局变量或者 Redis 存起来快过期了再重新获取不要每次发消息都去换一次。我见过有团队直接把getAccessToken写在每次发送前调用结果一天下来接口频繁报45009之类的频率限制错误。这里顺便把热搜词里“code 换 token”这个说法理清楚。小程序登录时前端通过wx.login拿到code后端拿code换的是openid和session_key这是登录态的一部分。而订阅消息发送需要的access_token是“接口调用凭证”跟用户身份没有直接关系。两条链路完全不同不要搞混。3.2 组装订阅消息发送请求获取access_token之后调用POST https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_tokenACCESS_TOKEN请求体结构如下{ touser: 用户openid, template_id: 订阅消息模板ID, page: pages/order/detail?id123, data: { thing1: { value: 订单已发货 }, character_string2: { value: SF1234567890 }, time3: { value: 2025-06-01 10:00 } }, miniprogram_state: formal, lang: zh_CN }data里的键必须和模板中定义的字段名一致不能随便起名。比如模板里是thing1你就只能写thing1。不同字段类型有长度限制thing类型最多 20 个中文字符number类型最多 32 位数字character_string类型最多 32 个字符time必须是标准时间格式phrase类型一般不超过 5 个汉字。超长会直接报47003参数错误。page字段是用户点击订阅消息后跳转到的小程序页面路径这里要注意必须是已经存在的页面否则也会报错。miniprogram_state有三个值formal正式版、trial体验版、developer开发版。如果小程序还没发布你要在开发环境自测应填developer或trial填formal在未上线版本上是无法正确跳转的。如果后端用的是 PHP可以用 curl 实现下面是一个简化示例function sendSubscribeMessage($accessToken, $openId, $templateId, $page, $data) { $url https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token . $accessToken; $data [ touser $openId, template_id $templateId, page $page, data $data, miniprogram_state formal, lang zh_CN ]; $ch curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_HTTPHEADER, [Content-Type: application/json]); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_UNICODE)); $response curl_exec($ch); curl_close($ch); return json_decode($response, true); }3.3 返回码正确理解 0 和 43101微信接口返回errcode和errmsg。errcode为 0 表示发送成功。常见的非 0 状态码和原因如下返回码含义处理建议0发送成功无需处理40003openid 不正确检查是否传错用户标识40037模板ID不正确检查后台模板是否与前端授权模板一致41030page 路径不正确检查跳转页面路径是否存在43101用户拒收或订阅额度不足一次性订阅最常见需重新引导订阅47003data 参数类型或格式错误检查字段类型和长度45009接口调用频率超限检查 access_token 缓存和发送频率控制这里重点说 43101。用户没点过授权、授权被用户关闭、一次性订阅额度已经用完都会返回这个码。很多项目第一次上线时用户授权后发送失败查来查去发现是后端把用户的 openid 拿错了或者前后端用了不同的模板 ID。排查顺序建议是先确认 openid 正确再确认模板 ID 是用户授权时传的那个最后看返回码的完整信息。4. 长期订阅的申请路径与次数管理长期订阅虽然诱人但实际落地时会遇到比一次性订阅更繁琐的审核和管理工作。这里把申请路径和次数管理的关键点讲清楚。4.1 先确认类目有没有资格打开小程序管理后台进入“功能 - 订阅消息”页面新增模板时如果能搜到长期订阅类别说明你的主体类目有资格搜不到后面就不用继续了。长期订阅目前主要覆盖政务、医疗、交通、金融、教育等公共服务领域。个人主体、普通商贸主体基本不在此列。如果你的业务确实属于公共服务范畴但后台看不到长期订阅入口可以先检查小程序认证主体和当前服务类目是否匹配必要时调整服务类目并等待审核。这里要有一点心理准备类目审核和长期订阅模板的审核都需要时间不要把整个项目的时间线卡在这上面。4.2 模板内容审核要注意什么长期订阅模板的关键词和内容结构一旦确定推送时不能随意改动。模板里每个字段的语义要和实际推送内容强相关比如“政策名称”“生效时间”“办理进度”这种。关键词不要带营销词汇不要出现“优惠”“折扣”“点击领取”等字眼。长期订阅的优点是可多次触达但这也意味着微信对内容合规的审查会更严格。一旦被用户投诉或者被系统判定为骚扰影响的不只是模板权限严重时整个小程序的消息能力都会被限制。4.3 订阅次数管理与防打扰策略用户对长期订阅模板授权后会获得一批可下发次数。这个次数是有限的不是无限发。所以后端最好维护一张用户订阅状态表记录每个用户对每个长期模板的剩余可用次数。每次推送前检查一下剩余次数避免把额度一次性刷完。真正做的时候还要想清楚防打扰策略。长期订阅的额度虽然比一次性订阅宽裕但用户容忍度是有限的。同一周内推送超过两三条通知用户的关闭率会明显上升。比较好的做法是把用户可能关心的通知合并成一条比如每周一次的汇总报告而不是每条业务动作都单独推一条。我在数据上看过高频消息的关闭率是低频消息的三倍以上这个数字很能说明问题。5. 常见问题与排查心得最后把实际开发中最常踩的几个坑集中说一下都是真实项目里反复出现过的。5.1 用户明明点了允许后端还是发送失败先别急着找微信客服。大概率是两种情况一是模板 ID 对不上前端授权时传的模板 ID 和后端发送时用的模板 ID 不是同一个二是用户 openid 取错了尤其是多端登录的场景一个用户可能在不同小程序账号下有不同 openid。排查方法很简单在后端发送接口的请求日志里把touser、template_id、errcode全部打出来逐个核对。5.2 一次性订阅额度什么时候会被消耗很多团队以为“发送失败不消耗额度下次还能重试”实际不是这样。只要调用了发送接口且返回0成功额度就会扣掉。如果返回43101则说明原本就没有可用额度。还有一种情况要注意发送接口返回成功之后消息也不一定必然进入用户会话如果订阅消息的page跳转路径失效用户点不进去体验上也算“发了一条废消息”。所以每次发送前要确保跳转页面可用。5.3 长期订阅什么时候会用不了除了类目白名单限制外长期订阅还有一个容易被忽略的问题用户首次授权后如果长期不打开小程序订阅次数用完之后你在后台再发就会收到43101。这时候需要想办法再次触达用户比如在用户进入小程序处理关键业务时增加一个“重新订阅”的操作入口。注意这里不能用一次性订阅的逻辑来替代长期订阅因为一次性订阅在根本没点过授权的情况下不会产生可用额度。5.4 调试阶段的几个实用技巧在微信开发者工具里可以手动模拟订阅结果在“模拟操作”面板中把订阅操作的返回值设成“接受”或“拒绝”不用每次都真机扫码。真机调试时用测试号或者把miniprogram_state设成developer配合开发版小程序使用能看到完整的消息链路。如果要用抓包工具查看后端请求注意区分小程序前端请求和服务器后端请求。订阅消息发送是服务端发起的跟小程序前端的网络请求不在同一条链路里。提示正式上线前一定要用真实账号做一次端到端测试从用户点击订阅、后端发送、用户点击消息跳转页面全流程走一遍。很多问题都是到了这一步才暴露的建议提前规划测试时间。在实操中的体会我在实际项目里最顺的一次消息触达是把订阅弹窗完全嵌进用户交易流程里。用户下单后页面上放一个“订阅订单状态通知”的按钮用户点击后弹授权接受率能做到七成以上。而在冷启动或者首页直接弹窗接受率往往只有两成。这个差别不是接口层面的问题而是产品设计层面的问题。订阅消息能不能成为有用的触达工具很大程度上取决于你愿不愿意花心思把订阅时机和用户当下的需求结合起来。另外想说模板和前后端联调顺序也很重要。我的习惯是先在小程序后台把模板配好再写前端订阅引导最后做后端发送逻辑。如果顺序反了会出现前端已经弹了授权、后端模板还没配好的尴尬情况联调时浪费不少时间。希望这篇记录能帮正在做订阅消息的你省下一些排查时间。
返回列表