·更新于 2026年10月25日· 27 次浏览 微信小程序广告Node.jsRedisMongoDB工程实践BUG解决

微信小程序激励视频回调丢失复盘:看完广告没解锁的兜底设计

一次用户反馈让我意识到,激励视频不能只信 success 回调。把广告完成当成不可信事件,用任务状态、幂等锁和补发入口兜底,才更稳。

微信小程序激励视频回调丢失复盘:看完广告没解锁的兜底设计 封面
ZHOUYI

作者

ZHOUYI

前阵子有用户反馈:在小程序里看完激励视频,进度条也走完了,但内容没有解锁。第一反应是广告回调没触发,但复现时又时好时坏。这类问题很像支付回调:用户侧“已完成”,服务端却可能没收到确定信号。于是我把这次接入当成一次小型发奖系统来复盘。

不要把前端 success 当唯一凭证

激励视频常见的问题是:用户关闭弹窗、网络抖动、广告平台回调延迟,或者前端拿到 success 后请求服务端失败。如果解锁逻辑只依赖广告回调,就会出现“看了但没发奖”。更稳的做法是:广告完成只作为触发条件,真正解锁要看服务端任务状态,具体字段和错误码以官方文档为准。

一次解锁任务:先建单,再发奖

  1. 用户点击解锁时,服务端生成一条 pending 状态的 UnlockTask,记录用户、内容、来源和过期时间。
  2. 客户端拿到 taskId 后再拉起激励视频,避免无任务发奖。
  3. 广告 success 回调携带 taskId 请求服务端确认,而不是直接本地解锁。
  4. 服务端用 Redis 做短时幂等锁,防止重复请求并发写入。
  5. 最终以 MongoDB 状态从 pending 变 done 为准,并写入解锁时间。
js
const lockKey = `ad:unlock:${userId}:${taskId}`;
const locked = await redis.set(lockKey, '1', 'NX', 'EX', 300);
if (!locked) return { unlocked: true, reason: 'duplicate' };
const updated = await UnlockTask.findOneAndUpdate(
  { _id: taskId, userId, status: 'pending' },
  { $set: { status: 'done', unlockedAt: new Date() } },
  { new: true }
);
if (!updated) return { unlocked: false, reason: 'invalid_task' };
return { unlocked: true };

回调丢失时,给用户一条补发路径

即使主链路稳了,也要准备兜底:页面上保留“已完成广告?点此刷新解锁”的按钮。点击后重新查询任务状态,如果任务未过期且广告观看记录存在,就尝试补发;如果信息不足,则记录异常并引导用户联系客服。补发接口同样要走幂等,不能因为用户多点几次就重复解锁。

“广告回调和支付回调一样:可以期待,但不能全信。工程上要有凭证、状态机、幂等锁和人工或自动兜底。”


这次复盘后,我把小程序里的激励视频解锁从“前端事件驱动”改成了“服务端任务驱动”。表面上多了一次请求和一张任务表,但用户投诉明显少了。对小程序、支付、广告这类涉及权益发放的场景,慢一点不怕,怕的是没有边界和兜底。

Guestbook

留言

若这篇文章也曾停在你心上,留一行字吧,我会看的。

先确认一下邮箱

多这一步,是为了少些机器骚扰,也让我能更踏实地读每一条真人写下的字。验证码 10 分钟内有效;同一邮箱 60 秒内只能发一封。

本文留言

共 0 条已加载 0 条

这里还静悄悄的——愿意做第一个留下脚印的人吗?