在微信生态里做营销裂变,砍价活动一直是转化率较高的玩法之一。用户通过公众号底部菜单进入活动页,发起砍价后把链接分享到微信群或朋友圈,好友点击助力,价格一步步往下砍,砍到底价即可下单。整个流程涉及自定义菜单配置、网页授权获取用户信息、分享接口调用以及后端助力逻辑处理,本文把这些环节逐一拆开讲清楚。

自定义菜单的配置与点击事件处理
自定义菜单分为两种类型:一种是 click 类型,点击后微信会把事件推送到开发者服务器;另一种是 view 类型,直接跳转到配置的网页地址。对于砍价活动这种需要携带用户身份的场景,两种方式都可以用,但推荐的做法是使用 view 类型直接跳转到活动落地页,因为 click 类型推送事件后还需要在客服消息里返回一个图文或链接,多了一步跳转,体验上会打折扣。
如果选择 view 类型,可以直接通过微信公众平台后台手动配置菜单,填写活动页地址即可。如果菜单需要根据不同用户动态展示,或者需要批量管理多个公众号的菜单,就要通过接口创建。调用创建菜单接口时,需要注意 access_token 的获取与缓存,token 有效期为两小时,必须全局缓存而不是每次请求都重新获取,否则容易触发频率限制。
下面是通过接口创建一个包含砍价活动入口的菜单示例:
{
"button": [
{
"type": "view",
"name": "砍价0元购",
"url": "https://你的域名.com/bargain/entry"
},
{
"type": "click",
"name": "我的活动",
"key": "MY_BARGAIN"
}
]
}如果用的是 click 类型,当用户点击菜单时,微信服务器会向开发者配置的服务器地址推送一条 XML 格式的消息,其中 MsgType 为 event,Event 为 CLICK,EventKey 就是配置时填的 key。服务端解析这条消息后,可以回复一条带链接的图文消息,引导用户进入活动页。PHP 的处理示例如下:
$xml = file_get_contents('php://input');
$data = simplexml_load_string($xml);
if ($data->MsgType == 'event' && $data->Event == 'CLICK'
&& $data->EventKey == 'MY_BARGAIN') {
$openid = $data->FromUserName;
$link = 'https://你的域名.com/bargain/entry?openid=' . $openid;
// 组装图文消息回复,引导用户进入砍价页
}网页授权与活动页面的用户身份识别
砍价活动必须知道当前用户是谁,否则无法判断是发起人还是助力好友,也无法防止同一个人反复助力。这就需要用到微信的网页授权机制。把活动页链接构造为授权跳转地址,用户点击后先跳转到微信的授权页面,同意后微信会带上 code 参数重定向回活动页,服务端再用 code 换取 access_token 和用户 openid。
授权分两种作用域:snsapi_base 是静默授权,用户无感知,只能拿到 openid;snsapi_userinfo 需要用户手动确认,可以额外拿到昵称和头像。砍价活动建议使用 snsapi_userinfo,因为活动页上需要展示砍价人的头像和昵称,增强真实感和社交传播效果。授权链接的格式如下:
https://open.weixin.qq.com/connect/oauth2/authorize ?appid=你的APPID &redirect_uri=活动页地址(需UrlEncode) &response_type=code &scope=snsapi_userinfo &state=STATE#wechat_redirect
拿到 code 后调用接口换取用户信息,注意 code 只能使用一次且五分钟内有效,换取到的 access_token 与公众号的全局 access_token 是两回事,不要混淆。用户信息拿到后写入会话或生成自己的登录态,后续所有接口请求都基于这个登录态操作。这里有一个常见的坑:redirect_uri 的域名必须在公众号后台配置为网页授权域名,且文件校验要通过,域名带端口或不带 www 都可能导致授权失败,上线前务必逐项核对。
// 用 code 换取用户信息
$url = "https://api.weixin.qq.com/sns/oauth2/access_token?"
. "appid={$appid}&secret={$secret}&code={$code}"
. "&grant_type=authorization_code";
$res = json_decode(file_get_contents($url), true);
if (isset($res['openid'])) {
// 拉取用户详情,拿到昵称头像
$infoUrl = "https://api.weixin.qq.com/sns/userinfo?"
. "access_token={$res['access_token']}"
. "&openid={$res['openid']}&lang=zh_CN";
$user = json_decode(file_get_contents($infoUrl), true);
// 写入会话,标记登录态
}砍价与助力接口的交互逻辑设计
活动页的核心数据结构一般包含三张表:活动商品表记录商品原价、底价、活动时间;砍价订单表记录发起人、当前价格、状态;助力记录表记录每一次助力的好友、砍掉金额、时间。用户点击发起砍价时创建一条订单,初始价格等于商品原价,然后分享出去等待好友助力。
助力接口需要处理几个关键判断:当前用户是否已经给这个订单助过力、用户是否是发起人本人、订单是否已砍到底价或已过期。砍掉的金额通常采用随机算法,但要让每次砍掉的金额总体上能覆盖原价到底价的差额,同时最后几刀金额逐渐变大,营造接近成功的紧张感。一个简化的随机算法示例如下:
function calcCutAmount($remain, $bottomPrice, $leftCount) {
// remain为剩余可砍金额,leftCount为剩余最少助力人数
$need = $remain - $bottomPrice;
$avg = $need / max($leftCount, 1);
// 在平均值上下浮动,保证整体可控
$cut = $avg * (0.5 + mt_rand() / mt_getrandmax());
$cut = min($cut, $need);
return round($cut, 2);
}分享功能通过 JS-SDK 实现。后端根据当前页面 URL 生成签名,前端调用 wx.config 注入权限,然后通过 wx.updateAppMessageShareData 和 wx.updateTimelineShareData 自定义分享标题、描述和图片。分享出去的链接要带上发起人的订单号参数,好友打开后授权识别身份,判定为助力场景就直接展示帮砍按钮。需要注意自定义分享链接时仍然只能分享当前域名下的页面,不能伪造其他域名,且分享内容的图片建议使用 300 像素以上的正方形图,否则缩略图会模糊。
wx.config({
debug: false,
appId: '你的APPID',
timestamp: ts,
nonceStr: nonce,
signature: sig,
jsApiList: ['updateAppMessageShareData', 'updateTimelineShareData']
});
wx.ready(function () {
wx.updateAppMessageShareData({
title: '帮我砍一刀,0元带回家',
desc: '就差你这一刀了,快来帮我砍价',
link: shareUrl,
imgUrl: 'https://你的域名.com/img/share.jpg'
});
});防刷机制与活动稳定性保障
砍价活动上线后最怕的就是被刷。常见的刷法包括:同一个人用多个小号反复助力、用脚本模拟微信 UA 请求助力接口、分享到接活群里批量互砍。应对思路是多维度设置限制条件。第一层是身份校验,助力必须基于真实网页授权拿到 openid,一个 openid 对同一订单只能助力一次,数据库层用唯一索引兜底,而不只依赖业务代码判断。第二层是设备与行为分析,记录助力的 IP 和设备特征,同一 IP 短时间内大量助力直接拦截。第三层是业务规则,比如每个用户每天最多助力三次、新注册用户助力权重降低等。
除了防刷,还要考虑并发问题。热门活动的助力请求可能瞬间涌入,砍价金额的计算和更新必须在数据库事务中完成,避免两个好友同时助力导致金额计算错乱。可以借助 Redis 做分布式锁,锁的粒度是订单号,保证同一订单的助力操作串行执行。同时助力成功后通过模板消息或订阅消息通知发起人,告诉他又被砍掉了多少,这种即时反馈能显著提升发起人继续分享的动力,形成传播的正循环。
最后提醒一点,砍价活动涉及诱导分享的边界问题,活动文案里不要出现强制分享才能完成的表述,底价设置的让利幅度要真实,避免被用户投诉虚假营销导致公众号被处罚。做好活动预热、页面的加载速度优化以及客服话术准备,一场砍价活动才能真正跑出裂变效果。