导读:本期聚焦于巫师创作的《微信公众号用户取消关注事件怎么处理?unsubscribe事件推送机制与数据统计详解》,敬请观看详情。公众号掉粉了,后台却没有任何记录?微信服务器在用户取消关注时会推送unsubscribe事件,很多开发者只处理了subscribe却忽略了取消关注的消息推送。本文详细讲解unsubscribe事件的XML报文结构、接收验证方法,以及如何在服务端更新用户关注状态、记录取关时间并搭建留存率统计体系。文中还会分析常见坑,比如用户快速取关再关注导致状态错乱、事件重试引发的数据重复统计等问题,并给出对应的解决代码,帮助你把粉丝画像和留存分析做得更准确。

做微信公众号后端开发时,subscribe(用户关注)事件一般都会认真处理,毕竟新增粉丝是运营最关心的指标。但取消关注的unsubscribe事件往往被一笔带过,甚至直接返回空字符串糊弄过去。等到运营同事拿着后台数据问“这个月掉粉多少、哪些人流失了”,才发现数据库里根本没记录。这篇文章就来完整讲讲unsubscribe事件的推送机制、服务端处理逻辑,以及如何基于取关数据做留存统计。

微信公众号用户取消关注事件怎么处理?unsubscribe事件推送机制与数据统计详解

一、unsubscribe事件的推送机制与XML报文

当用户在公众号会话界面点击右上角取消关注,或者通过其他途径取消关注时,微信服务器会向公众号配置的服务器URL推送一条事件消息,MsgType为event,Event为unsubscribe。这条推送与普通文本消息走同一个接口,所以必须在消息处理入口处做分支判断。

标准的报文结构如下:

<xml>
  <ToUserName><![CDATA[gh_abcdef123456]]></ToUserName>
  <FromUserName><![CDATA[oX1_yyyyyyyyyyyy]]></FromUserName>
  <CreateTime>1718000000</CreateTime>
  <MsgType><![CDATA[event]]></MsgType>
  <Event><![CDATA[unsubscribe]]></Event>
</xml>

几个字段需要特别注意:ToUserName是公众号原始ID,FromUserName是用户的openid,这也是唯一能定位用户的凭证。unsubscribe事件不像click、scan等菜单事件那样带EventKey参数,报文非常简洁,你只能拿到openid和事件时间。

还有一点容易被忽视:如果用户“取关后马上又重新关注”,你会在极短时间内先后收到unsubscribe和subscribe两条推送,网络重试时甚至可能出现乱序到达。因此服务端处理时不能假设事件是严格按时间顺序来的,写入数据时要带上CreateTime做兜底校验。

二、服务端接收与处理逻辑实现

处理逻辑的核心是把用户的关注状态落库。推荐用一个user表记录openid、关注状态、首次关注时间、最近关注时间和取关时间,这样既能算留存也能算流失。下面以常见的Web框架思路给出示例代码(以PHP为例,Java、Python同理):

<?php
// 接收微信推送的原始POST数据
$postStr = file_get_contents("php://input");
libxml_disable_entity_loader(true); // 防XXE,低版本PHP可用
$postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);

if ($postObj->MsgType == 'event' && $postObj->Event == 'unsubscribe') {
    $openid  = (string)$postObj->FromUserName;
    $EventTime = (int)$postObj->CreateTime;

    // 防止乱序:只有当本次事件时间晚于库中记录的关注时间才更新
    $user = Db::query("SELECT subscribe_time FROM wx_user WHERE openid = ?", [$openid]);
    if ($user && $user['subscribe_time'] < $EventTime) {
        Db::execute(
            "UPDATE wx_user SET subscribed = 0, unsubscribe_time = ? WHERE openid = ?",
            [$EventTime, $openid]
        );
        // 同时写入一条取关日志,用于后续统计明细
        Db::execute(
            "INSERT INTO wx_unfollow_log (openid, event_time) VALUES (?, ?)",
            [$openid, $EventTime]
        );
    }
    // 微信要求:事件推送可直接回复success或空串
    echo 'success';
    exit;
}

几个细节值得展开说。第一,回复内容必须是success或空字符串,如果5秒内没收到有效响应,微信会重试推送三次,这就是很多开发者发现取关日志里出现重复记录的原因。解决方案有两个:一是加幂等处理,用openid加事件时间去重;二是把业务逻辑放入消息队列异步执行,接口立即返回success。

第二,不要在取关时调用用户信息接口去补全昵称头像。用户已经取关,通过openid拉取用户信息的接口会返回未关注状态,昵称等字段拿不到(2017年12月之后官方就限制了),所以用户资料应该在关注或互动时及时保存。

第三,别忘了同时维护取关流水表。只更新用户表的当前状态会丢失历史,无法回答“这个用户取关过几次、上次是什么时候”这类问题。流水表加状态表的双表结构,是做粉丝留存分析的基础。

三、基于取关数据的留存率统计

数据落库之后,统计才有意义。留存率的经典算法是:某天新增关注的一批用户,在之后第N天仍处于关注状态的比例。结合前面的表结构,可以用一条SQL算出按日取关数量:

-- 统计最近30天每日取关人数
SELECT
    FROM_UNIXTIME(event_time, '%Y-%m-%d') AS day,
    COUNT(*) AS unfollow_count
FROM wx_unfollow_log
WHERE event_time >= UNIX_TIMESTAMP(DATE_SUB(CURDATE(), INTERVAL 30 DAY))
GROUP BY day
ORDER BY day;

净增长指标则等于当日新增关注数减去当日取关数。如果发现某天掉粉异常,可以按渠道细分排查:比如给关注来源打标(扫二维码关注时EventKey里会带场景值),取关时就能反推哪个渠道引来的粉丝质量差。

还有一种常见做法是把取关事件接入统一的分析系统。在unsubscribe处理逻辑里推送一条消息到Kafka或者调用内部统计接口,后续由大数据侧完成漏斗分析、用户画像关联。对于多公众号矩阵,统计系统还要按appid维度区分,避免不同账号的数据混在一起。

最后提醒一点,数据口径要和运营对齐。用户取关又重新关注,如果按流水统计会算成一次掉粉加一次新增,按状态表算则表现为粉丝数不变。两种口径没有对错,但必须固定一种并在报表中注明,否则每次核对数据都会出现对不上的情况。把unsubscribe事件当成一条普通的业务消息认真处理,粉丝全生命周期数据才能完整,后续的召回、分层运营也才有数据可依。

微信公众号开发unsubscribe事件用户取消关注修改时间:2026-09-03 20:07:05

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260903/49780.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。