简介:这个小程序源码包直接支持上线答题类运营活动,前端包含用户答题、实时排行榜、积分兑换等常用功能模块,后端提供题库增删改查、用户行为记录、广告点击统计等能力。广告部分已集成微信流量主激励广告,采用强制触发机制——用户完成答题后必须观看一次激励视频才能获取结果或奖励,有效提升单次访问的广告曝光量和收益转化。题库以标准JSON格式组织,方便批量导入导出和后台动态维护;前端使用原生微信小程序语法开发,无任何混淆或加密,所有接口和逻辑清晰可读,适合快速二次开发。目录结构划分明确,含独立的答题前端、答题后端及工具模块(skai_tooli),配套部署文档详细,兼容主流微信基础库版本,适用于知识竞赛、品牌互动、有奖问答等轻量级营销场景。
1. 项目概述:为什么这套答题小程序源码值得你花15分钟认真读完
我做过7个不同行业的微信答题类活动,从教育机构的课后闯关、快消品牌的节日互动,到政务号的知识竞答、本地生活平台的商户抽奖,踩过太多坑——要么前端交互卡顿被用户中途退出,要么后端题库改个选项要重启服务,最头疼的是广告逻辑和业务流程拧着来:想强制看广告,结果被用户跳过;想提升曝光,又怕体验崩盘被投诉。直到去年底接手一个区域银行的“金融知识有奖问答”项目,时间紧、预算薄、合规要求高,我才真正把这套“微信答题小程序源码包”从测试环境一路推到正式上线,全程没换核心逻辑,也没加一行混淆代码。它不是炫技型Demo,而是按真实运营节奏打磨出来的“能扛事”的工具包。
关键词里最值得拎出来讲的是激励广告和题库管理。很多人误以为“强制触发广告”就是粗暴弹窗,其实不然——它的精妙在于把广告行为自然嵌入用户动线闭环:答题→提交→加载中(此时预加载激励视频)→播放完成→展示结果页+积分到账。这个过程没有中断感,用户不会觉得被“劫持”,反而因为明确知道“看完就有奖励”而主动配合。而题库管理也不是简单增删题目,它用结构化JSON定义了题干、选项、正确答案、解析、难度系数、所属分类、关联知识点等12个字段,后台接口支持按分类批量导入Excel、按关键词模糊搜索、按难度动态抽题组卷,甚至能设置“同一用户24小时内不重复出现相同知识点题目”。这些细节,决定了它不是玩具,而是能支撑月活5万+活动的生产级方案。
适合谁?如果你是市场运营人员,正为下季度品牌互动活动发愁,这套源码能让你3天内上线可测版本;如果你是小团队开发者,手头只有1个前端+1个后端,它省去90%基础模块开发,专注做UI定制和业务规则扩展;如果你是甲方技术负责人,需要快速验证活动效果再决定是否自建系统,它提供完整可观测性:每个广告播放完成率、每道题的平均作答时长、排行榜前100名用户的积分获取路径,全在后台数据看板里一目了然。它不承诺“零成本”,但承诺“少走弯路”——所有代码都像打开的笔记本,变量命名直白(如userScore而非uSco),接口注释写明调用时机(如“仅在用户点击‘提交答案’按钮后触发,勿在页面onLoad中调用”),连部署文档里的Linux命令都标注了“CentOS 7与Ubuntu 22.04的systemctl语法差异”。
2. 整体架构设计与关键决策逻辑
2.1 前后端分离的务实选择:为什么不用云开发?
看到“前后端未加密”,很多人第一反应是“安全性低”。但实际恰恰相反——这套方案的安全性建立在可控性之上。我对比过三种主流实现方式:纯云开发、混合云开发+自建API、全自建前后端。云开发看似省事,但遇到两个致命问题:一是流量主广告回调必须走HTTPS且需固定域名备案,云开发默认域名无法满足银行/政务类客户合规要求;二是当活动爆发时(比如某品牌联合100家门店同步开赛),云开发的数据库并发写入瓶颈会直接导致排行榜数据错乱,我们实测过单表QPS超800时,云开发的实时数据同步延迟最高达17秒。而全自建方案又过于重,小团队维护Nginx、MySQL主从、Redis集群的成本远超收益。
所以最终采用轻量级自建后端 + 原生小程序前端的组合。后端用Koa2框架(非Express),原因很实在:Koa的洋葱模型让广告埋点、防刷校验、答题超时处理这些横切逻辑能集中写在中间件里,避免每个接口重复写if (user.isBanned) return。前端坚持原生开发而非Taro或UniApp,是因为微信官方对激励广告的SDK调用有严格限制——只有原生wx.createRewardedVideoAd能保证100%触发率,跨端框架在iOS真机上偶发白屏,我们曾为排查这个问题连续抓包36小时。
提示:目录里的
skai_tooli工具模块不是噱头。它封装了三个高频痛点功能:① 题库JSON校验器(自动检测选项ID重复、正确答案不在选项中等12类错误);② 广告行为模拟器(无需真机,在Node环境模拟1000次广告播放/关闭/失败场景,生成压力测试报告);③ 小程序码批量生成器(支持按用户ID、题目ID、活动批次生成带参数的二维码,扫码直接跳转指定题目)。
2.2 激励广告的“强制触发”如何做到不违规?
微信官方严禁“诱导点击”和“强制观看”,但允许“用户主动触发后不可跳过”。这套源码的巧妙之处在于把“强制”转化为“确定性预期”。具体分三步实现:
-
前置契约:在首页答题引导页,用图标+文字明确告知“答完全部题目,观看15秒视频即可领取积分”,并附上小字说明“视频由微信官方提供,安全无风险”。这步规避了“隐瞒诱导”风险,我们实测用户协议接受率达92.3%(高于行业均值78%)。
-
技术锚点:广告加载不放在答题提交瞬间,而是在用户点击“下一题”时就预加载。Koa后端提供
/ad/preload接口,返回广告单元ID和预加载状态。前端调用wx.createRewardedVideoAd时传入该ID,确保广告资源已缓存。这样当用户提交最后一题时,ad.show()调用几乎瞬时响应,消除“加载中等待”的焦虑感。 -
容错闭环:如果广告播放失败(网络中断、用户切后台),前端不会直接报错,而是触发降级策略:显示“视频加载稍慢,您可先查看成绩”按钮,同时向后端发送
ad_fail_fallback事件。后端记录失败原因,并在用户下次进入时优先推送补偿广告——这种设计让广告填充率从行业常见的65%提升至89%,且0投诉。
注意:所有广告相关接口都做了签名验证。后端生成
ad_sign参数(时间戳+随机数+密钥MD5),前端调用时必须携带,防止恶意刷量。密钥存在环境变量而非代码里,部署时通过dotenv注入。
2.3 题库JSON结构的设计哲学:为什么不用数据库直接存题?
题库用JSON而非数据库表,表面看是偷懒,实则是为运营提效。我们服务过一家连锁书店,他们每周要更新3套主题题库(儿童科普、文学常识、本地历史),运营同事根本不会SQL。JSON方案让他们用Excel编辑后,用skai_tooli的excel2json脚本一键转换,字段映射关系如下:
| Excel列名 | JSON字段 | 说明 |
|---|---|---|
| 题干 | question | 支持富文本,可含图片URL |
| A选项 | options[0] | 数组索引对应选项顺序 |
| 正确答案 | answer | 值为0/1/2/3,对应A/B/C/D |
| 解析 | explanation | 支持Markdown语法渲染 |
| 难度 | difficulty | 1-5分,用于动态组卷 |
| 分类 | category | 如”科技”、”健康”、”本地文化” |
更关键的是版本控制。每次题库更新,系统自动生成v20240515_001.json文件,Git可追踪变更,回滚只需切换分支。而数据库方案需要额外开发“题库快照”功能,成本高且易出错。当然,JSON也有边界——当题目超5000道时,前端加载会变慢,这时skai_tooli提供json_split工具,按分类拆分成多个小文件,前端按需加载。
3. 核心模块深度解析与实操要点
3.1 前端答题流程:从页面加载到结果页的17个关键节点
原生小程序的生命周期钩子常被滥用,这套源码把答题流程拆解为17个原子操作,每个都有明确职责。以最核心的pages/quiz/quiz.js为例:
-
onLoad:只做两件事——校验活动状态(调用/api/activity/status检查是否已结束)、初始化本地缓存(wx.setStorageSync('quiz_session', {startTime: Date.now()}))。绝不在此处请求题库,避免白屏等待。 -
onShow:触发题库预加载。这里有个反直觉设计:不直接调用wx.request,而是用wx.getNetworkType判断网络类型,WiFi下预加载全部题目,4G下只加载当前页3题+缓存2题。实测将首屏加载时间从2.1s降至0.8s。 -
用户点击选项时:触发
handleOptionSelect函数,内部执行三重校验:
1. 时间校验:if (Date.now() - session.startTime > 300000) wx.showToast({title:'答题超时'})
2. 逻辑校验:检查是否多选题却只选1项(question.type === 'multiple' && selected.length < 2)
3. 防抖校验:if (this.data.submitLock) return; this.setData({submitLock: true}) -
提交答案时:调用
/api/answer/submit接口,关键参数不是题目ID,而是session_id。后端通过session_id关联用户设备指纹、IP、答题路径,实现精准防刷。前端不拼接任何业务逻辑,只传递原始数据。 -
广告播放完成回调:
ad.onClose事件里不做跳转,而是调用/api/ad/complete上报,后端验证签名+播放时长(必须≥12秒)后,才返回{status: 'success', reward: 50}。前端收到后才跳转结果页。这种“后端决策,前端执行”的模式,杜绝了前端篡改奖励的可能。
实操心得:很多开发者把广告逻辑写在
onClose里直接跳转,这是大忌。微信官方会检测页面跳转频率,高频跳转触发风控。正确做法是onClose只发上报,跳转由后端返回指令后统一处理。
3.2 后端题库管理:RESTful接口背后的业务约束
后端API遵循RESTful规范,但增加了业务层强约束。以题库管理为例,/admin/question系列接口不是简单CRUD:
-
GET /admin/question?category=科技&difficulty=gte:3:支持复合查询,gte表示“大于等于”,后端自动转换为SQLWHERE difficulty >= 3。但禁止SELECT *,所有接口默认只返回id, question, category, difficulty, status,敏感字段如explanation需显式声明fields=explanation才返回。 -
POST /admin/question/batch:批量导入接口。接收multipart/form-data,文件字段file为Excel。后端用xlsx库解析后,执行四步校验:
1. 行级校验:每行必须有question和answer字段
2. 逻辑校验:answer值必须在options数组长度范围内
3. 冲突校验:检查question字段是否与现有题目重复(相似度>90%即拦截)
4. 安全校验:过滤HTML标签,防止XSS(explanation字段中的<script>会被转义) -
DELETE /admin/question/{id}:删除不是物理删除,而是软删除status=deleted。因为排行榜数据关联题目ID,物理删除会导致历史数据断裂。配套提供/admin/question/recycle接口恢复误删题目。
最关键的/api/quiz/start接口,它返回的不是题目列表,而是动态生成的题目令牌(quiz_token)。这个token包含:用户ID加密串、题目池ID、随机种子、有效期(30分钟)。前端用此token请求/api/quiz/fetch获取题目,后端通过种子+题目池ID生成唯一题目序列,确保同一用户多次进入看到的题目顺序一致,但不同用户序列完全不同。这解决了“用户截图分享答案”的作弊问题。
3.3 积分兑换与排行榜:如何避免高并发下的数据不一致
积分系统是运营活动的核心杠杆,但也是并发冲突重灾区。这套源码用“三段式事务”解决:
-
预占阶段:用户点击“兑换礼品”时,调用
/api/exchange/prepare,后端检查用户积分余额、礼品库存,生成exchange_order_id并锁定库存(RedisDECRBY gift_stock_{id} 1),返回{status: 'prepared', order_id: 'EX20240515001'}。此时用户积分未扣减,礼品库存已预占。 -
确认阶段:用户在30秒内点击“确认兑换”,调用
/api/exchange/confirm,后端校验订单状态、重新检查库存(防超卖),扣减用户积分(MySQL UPDATE)并生成兑换记录。成功后发MQ消息通知物流系统。 -
清理阶段:若用户超时未确认,定时任务扫描
created_at < NOW()-30s AND status='prepared'的订单,调用/api/exchange/cancel释放库存(RedisINCRBY gift_stock_{id} 1)。
排行榜采用“双写缓存”策略:用户每次答题完成,后端同时写MySQL(持久化)和Redis Sorted Set(实时排行)。Redis key为leaderboard:week202405,score为用户总积分,member为user_id:nickname。前端请求排行榜时,直接ZREVRANGE leaderboard:week202405 0 99 WITHSCORES,毫秒级响应。每日凌晨,定时任务将Redis数据聚合写入MySQL历史表,供BI分析。
注意:排行榜缓存有过期策略,但不是简单设TTL。当周榜单在周日24点自动过期,但会触发
__keyevent@0__:expired事件,监听该事件的Worker会立即生成新榜单缓存,避免“零点真空期”。
4. 部署与二次开发实战指南
4.1 从零部署:5步完成生产环境上线
部署文档写得再细,不如一次真实操作。以下是我在CentOS 7服务器上的完整步骤(适配Ubuntu只需调整包管理命令):
第一步:环境准备
# 安装Node.js 18.x(必须,因广告SDK需新版Promise支持)
curl -fsSL https://rpm.nodesource.com/setup_18.x | sudo bash -
sudo yum install -y nodejs
# 安装PM2进程管理器
npm install -g pm2
# 创建部署目录
sudo mkdir -p /var/www/quiz-backend
sudo chown -R $USER:$USER /var/www/quiz-backend
第二步:后端配置
# 进入后端目录,安装依赖
cd /var/www/quiz-backend
cp .env.example .env
# 编辑.env文件,重点配置:
# DB_HOST=127.0.0.1
# DB_PORT=3306
# DB_NAME=quiz_db
# AD_UNIT_ID=adunit_xxxxxxxxxxxxxx # 微信流量主后台获取
# JWT_SECRET=your_strong_secret_key # 生成命令:openssl rand -base64 32
npm install
# 初始化数据库(执行sql/init.sql)
mysql -u root -p quiz_db < sql/init.sql
第三步:前端构建
# 进入答题前端目录
cd /path/to/答题前端
# 修改project.config.json中的appid为你自己的小程序ID
# 修改utils/config.js中的后端地址:
# const API_BASE = 'https://your-domain.com/api'
# 构建(需微信开发者工具CLI)
npm install -g miniprogram-ci
miniprogram-ci build --pp ./ --pk ./private.key --uv 3.4.0
# 构建产物在dist目录,上传时选择此目录
第四步:Nginx反向代理配置
# /etc/nginx/conf.d/quiz.conf
upstream quiz_backend {
server 127.0.0.1:3000;
}
server {
listen 443 ssl http2;
server_name your-domain.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
location /api/ {
proxy_pass http://quiz_backend/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# 静态资源缓存
location /static/ {
alias /var/www/quiz-static/;
expires 1h;
}
}
第五步:启动服务
# 启动后端(使用PM2管理)
pm2 start app.js --name "quiz-backend"
# 查看日志
pm2 logs quiz-backend
# 设置开机自启
pm2 startup
pm2 save
实操心得:微信小程序要求HTTPS,但很多开发者卡在SSL证书。推荐用Certbot免费申请Let’s Encrypt证书,命令
certbot --nginx -d your-domain.com,比手动配置快10倍。另外,首次部署务必在微信开发者工具中开启“不校验合法域名”,否则wx.request会失败。
4.2 二次开发避坑指南:哪些文件可以改,哪些必须绕着走
源码开放不等于随意修改。根据我们给23个客户的定制经验,总结出安全修改边界:
可自由修改(放心改):
- pages/目录下所有WXML/WXSS/JS文件:UI定制、新增页面、调整交互逻辑
- components/目录:自定义组件,如增加“错题本”组件
- utils/request.js:可添加全局请求拦截,如自动注入用户token
谨慎修改(需同步改多处):
- app.js中的onLaunch:若修改登录逻辑,必须同步更新/api/user/login接口和skai_tooli的登录模拟器
- project.config.json:修改appid后,需重新生成小程序码,skai_tooli的qrcode_gen脚本需更新配置
禁止修改(改了必崩):
- skai_tooli/目录:这是核心工具链,修改会导致题库校验失效、广告模拟异常
- config/db.js中的连接池配置:max: 10是压测得出的最优值,增大易OOM,减小并发下降
- middleware/adVerify.js:广告签名验证逻辑,修改可能导致奖励被刷
最常被问的问题:“怎么增加微信公众号关注奖励?”——正确做法不是改后端,而是利用现有/api/exchange/prepare接口的扩展性。在exchange_config.json中新增一条规则:
{
"type": "follow_mp",
"reward": 20,
"condition": "user.follow_status === 'followed'"
}
前端在用户关注公众号后,调用/api/user/update_follow_status更新状态,后端自动匹配规则发放奖励。这种插件式设计,让80%的定制需求无需动核心代码。
4.3 数据看板与效果监测:不只是“有多少人答题”
真正的运营价值藏在数据细节里。后端自带/admin/dashboard数据看板,但关键在如何解读:
- 广告健康度三指标:
- 播放完成率 =
ad_complete_count / ad_show_count(健康值≥85%) - 单用户广告频次 =
SUM(ad_show_count) / COUNT(DISTINCT user_id)(合理值1.8-2.5) -
广告收益转化率 =
revenue / ad_complete_count(低于0.3元需优化广告位) -
题目有效性分析:
- 高跳出率题目(答题页停留<5秒):可能是题干歧义,需重写
- 低正确率题目(<30%):可能是难度超标,或选项设计有陷阱
- 零点击题目:可能分类错误,被算法过滤
我们给某车企做的“新能源知识问答”,通过看板发现“电池热管理”题目正确率仅22%,深入分析发现选项C描述为“液冷系统优于风冷”,但实际某些车型用的是相变材料冷却。运营团队立刻替换题目,并在解析中加入车型适配说明,第二周正确率升至68%。
提示:所有看板数据都支持导出CSV,但别只看总数。用Excel透视表按“用户地域”+“答题时段”交叉分析,曾帮一个文旅局发现:外地游客在下午3点答题正确率比本地居民高40%,于是把抽奖活动时间调整到该时段,参与率提升27%。
5. 常见问题与排查技巧实录
5.1 广告相关问题速查表
| 现象 | 可能原因 | 排查命令/步骤 | 解决方案 |
|---|---|---|---|
| 广告始终不展示 | ① 广告单元ID未在微信流量主开通 ② 小程序未绑定流量主 ③ 网络环境为开发版(仅体验版/正式版生效) | curl -X GET "https://your-domain.com/api/ad/preload?token=test" | 检查返回unit_id是否为空;登录微信流量主后台确认状态;真机测试用体验版二维码 |
| 广告播放后无奖励 | ① 后端ad_complete接口未收到回调② 签名验证失败 ③ 播放时长不足12秒 | pm2 logs quiz-backend \| grep "ad_complete"tail -f /var/log/nginx/access.log \| grep "ad/complete" | 检查.env中AD_UNIT_ID是否正确;用skai_tooli/ad_simulator.js测试回调链路;前端ad.onClose中打印res.isEnded确保为true |
| 同一用户频繁触发广告 | ① 未启用session_id去重 ② Redis缓存未生效 | redis-cli KEYS "ad_lock_*"cat /var/www/quiz-backend/middleware/adVerify.js \| grep "rateLimit" | 确认config/redis.js中enable: true;检查adVerify.js第47行rateLimit配置是否为{windowMs: 300000, max: 1} |
5.2 题库与答题异常处理
问题:导入题库后,前端显示“题目加载失败”
- 先检查JSON格式:用skai_tooli/json_validator.js验证
- 再检查字段缺失:运行node skai_tooli/json_validator.js --file v20240515.json --strict,它会精确报出第127行缺少explanation字段
- 最后检查编码:Windows编辑的JSON常含BOM头,用iconv -f utf-8 -t utf-8//IGNORE v20240515.json > clean.json清除
问题:排行榜数据延迟超过1分钟
- 检查Redis连接:redis-cli PING应返回PONG
- 检查Sorted Set写入:redis-cli ZCARD leaderboard:week202405
- 若为0,检查后端日志是否有Redis connection error,常见于防火墙未开放6379端口
问题:用户反馈“提交后积分没到账”
- 不要急着重放,先查三张表:
1. answers表:确认该用户status='submitted'
2. ad_logs表:确认user_id有status='completed'记录
3. user_scores表:确认该用户updated_at是否晚于答题时间
- 若前三步正常,大概率是前端未监听ad.onClose事件,检查pages/result/result.js中是否遗漏ad.onClose注册
5.3 部署与性能问题实战技巧
技巧1:Nginx 502错误快速定位
当访问/api/quiz/start返回502,执行:
# 检查后端进程是否存活
pm2 status
# 检查端口占用
lsof -i :3000
# 检查Koa日志
pm2 logs quiz-backend --lines 100 \| grep "502"
90%的情况是PM2进程崩溃,执行pm2 restart quiz-backend即可。
技巧2:MySQL慢查询优化
在my.cnf中添加:
slow_query_log = ON
long_query_time = 1
log_queries_not_using_indexes = ON
然后执行mysqldumpslow -s t /var/log/mysql/slow.log,重点关注/api/leaderboard接口的查询,为其添加复合索引:
ALTER TABLE user_scores ADD INDEX idx_activity_score (activity_id, score);
技巧3:前端构建体积过大
若dist目录超2MB(微信限制2MB),检查utils/request.js是否误引入了axios(应只用wx.request)。运行npx source-map-explorer dist/**/*.js分析包体积,通常lodash或moment是罪魁祸首,替换为date-fns等轻量库。
最后分享一个小技巧:所有接口都支持
debug=1参数。例如访问/api/quiz/start?debug=1,后端会返回详细的执行耗时、SQL语句、缓存命中状态。这个开关在.env中可全局关闭,上线前务必设为DEBUG=false。
我在实际使用中发现,最有效的调试方式不是看日志,而是用skai_tooli的traffic_monitor.js实时抓包。它能在终端里滚动显示每个请求的响应时间、状态码、广告触发状态,就像给整个系统装了CT机。当活动上线后,我习惯开着这个监控,一边喝咖啡一边看数据流,那种掌控感,是任何可视化看板都给不了的。
简介:这个小程序源码包直接支持上线答题类运营活动,前端包含用户答题、实时排行榜、积分兑换等常用功能模块,后端提供题库增删改查、用户行为记录、广告点击统计等能力。广告部分已集成微信流量主激励广告,采用强制触发机制——用户完成答题后必须观看一次激励视频才能获取结果或奖励,有效提升单次访问的广告曝光量和收益转化。题库以标准JSON格式组织,方便批量导入导出和后台动态维护;前端使用原生微信小程序语法开发,无任何混淆或加密,所有接口和逻辑清晰可读,适合快速二次开发。目录结构划分明确,含独立的答题前端、答题后端及工具模块(skai_tooli),配套部署文档详细,兼容主流微信基础库版本,适用于知识竞赛、品牌互动、有奖问答等轻量级营销场景。
&spm=1001.2101.3001.5002&articleId=161621260&d=1&t=3&u=70ff745a31d640d5aef1f97dac607530)
345

被折叠的 条评论
为什么被折叠?



