简介Discuz!小程序源码是一套面向微信小程序开发者的社区论坛移动端解决方案基于Discuz!系统数据与接口可快速构建具备用户认证、帖子浏览、数据统计等能力的小程序应用。压缩包共266个文件约347KB以wxml、wxss、js、json等前后端文件为主——wxml负责页面结构wxss定义样式js处理业务逻辑json完成配置另含png图片、Git忽略规则、LICENSE授权说明及README入门指引目录结构清晰便于直接导入开发工具进行二次定制。已有219人学习下载。该源码提供了完整的前后端代码骨架开发者可参考其中接口调用方式与页面交互逻辑将Discuz!论坛能力迁移至移动端节省从零搭建的工作量同时也可作为学习小程序与后端数据库联动、理解社区系统移动化改造的实践素材适合有一定前端基础并希望拓展Discuz!移动场景的技术人员。1. 拿到 Discuz!小程序源码.zip 之后先确认它是给手机端论坛用的Discuz!小程序源码.zip 这个名字说明两件事第一压缩包里的代码是用原生微信小程序语法写的不是常见的那种套壳 H5第二它要对接的是 Discuz! 论坛系统也就是你站点的帖子、版块、用户体系仍然在 PHP 后端小程序端只是换了一个手机上的出入口。很多站长第一次拿到这种包以为解压上传就能用实际落地时至少涉及前端编译、接口鉴权、域名白名单三件事缺一件都跑不起来。这套方案适合已经有 Discuz! 论坛站点、想低成本做一个供移动端用户逛论坛的入口而不是让你从零去建一个新社区。它像是给老论坛做了一层新皮肤真正复杂的帖子数据、搜索、权限还在后端。2. 拆包看门道Discuz!小程序源码的目录结构、接口层与运行前提2.1 解压后的目录该长什么样前端工程与接口层各管什么拿到一个 Discuz! 小程序源码包第一步不是急着导入微信开发者工具而是先解压把里面的文件认一遍。常见的源码包结构大致是这样的app.js、app.json、app.wxss三个全局文件在根目录pages/目录下按功能拆分页面比如pages/index/是帖子列表、pages/forum/是版块、pages/detail/是帖子详情、pages/mine/是个人中心。有的包会附带一个utils/目录里面放 request 封装、时间格式化、登录态管理这些公共逻辑。如果你看到components/目录多半是自定义组件比如分享按钮、下拉刷新、发布入口。还有一类源码包会额外塞一个api/或server/目录里面放的是 PHP 接口文件那是给后端用的需要上传到 Discuz! 站点根目录而不是放进小程序工程里。这两部分的边界必须分清楚前端代码改完要预览只需要微信开发者工具后端接口文件则要 FTP 上传到服务器并且保证接口 URL 能被外网访问到。我见过有人把 PHP 文件当成小程序页面代码塞进pages/目录结果编译直接报错白折腾半小时。2.2 小程序端和 Discuz! 后端是怎么对话的API 网关与登录态Discuz! 本身没有为小程序提供官方标准接口所以市面上的 Discuz! 小程序源码绝大多数是通过在 Discuz! 插件体系里加一个 API 网关来工作的。常见做法是在站点根目录放一个api.php或者利用了plugin.php机制做的入口小程序端所有请求都打到这个文件上由它统一处理参数校验、调用 Discuz! 内部的帖子查询函数、返回 JSON 数据。这样做的好处是绕开了 Discuz! 原本的 HTML 模板渲染逻辑不用去解析页面 DOM天然适合小程序端。这个 API 网关通常需要支持两类接口一类是公开的读接口比如获取版块列表、获取帖子列表、获取帖子详情这类接口只读不改数据一般不要登录态适合游客浏览另一类是写接口比如发帖、回帖、点赞、收藏这类接口必须校验用户身份不然随便一个请求就能在你论坛上灌水。身份校验的手段在 Discuz! 体系里惯用的是 formhash 配合 cookie小程序端不像浏览器会自动带上 cookie所以需要在请求头里手动维护 cookie 字段。这一点写代码时一定要看清楚了很多半成品的源码包里发帖接口只是简单模拟了一下没有真正带上 cookie部署后会出现能看帖不能回帖的现象。2.3 运行前提服务器环境与小程序账号资质把源码包部署起来之前有几个硬性条件是绕不过去的。Discuz! 后端站点需要跑在 PHP 5.6 以上、MySQL 5.7 以上的环境里这跟你原来跑论坛的环境一致就行不需要额外装东西。小程序端则需要一个微信小程序账号个人主体可以注册但一些关键接口会有权限差异。比如获取用户手机号这个能力个人主体小程序以前无法直接调用后面微信改版后个人主体可以在用户主动授权的前提下用快速验证组件获取手机号但每次调用会产生费用。对于纯论坛场景我一般都建议先不要接手机号微信登录足够顶一个月活几万的小站点了等有实名或风控需求时再补上成本更可控。另外微信小程序要求所有请求域名必须配置到小程序后台的 request 合法域名里而且必须是 HTTPS 域名同时还要求域名已备案。这意味着你那台 Discuz! 服务器要挂 SSL 证书没有证书的话小程序开发工具里可以勾选“不校验合法域名”来调试但真机预览和正式上线是走不通的。这一步卡住了很多人我建议你在动手改代码之前先把https://你的域名/api.php这串地址在浏览器里打开一次能正常返回 JSON 或提示参数错误说明通信链路是通的再去碰小程序端代码。3. 把小程序跑在微信开发者工具里从导入到真机预览3.1 导入项目与基础配置appid、项目名与不校验合法域名打开微信开发者工具选择“导入项目”目录指向你解压出来的小程序工程根目录就是含app.json的那一层。AppID 可以先选择测试号但测试号意味着没有正式的 request 合法域名配置所以开发阶段必须勾选“不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书”。如果你手头有正式的小程序 AppID直接用正式 AppID 导入也行这时本地调试仍然建议勾选不校验域名毕竟你的 Discuz! 接口大概率还在用 IP 或临时端口。导入后第一件事是改app.js里的全局配置。一般源码会有一个globalData对象里面放着apiBaseUrl或者siteUrl字段把它的值改成你的 Discuz! 站点域名注意以https://开头结尾不要带斜杠。改完保存直接编译看控制台有没有明显报错。如果报错指向app.json通常是页面路径不对说明这个源码包依赖了缺失的页面文件这时候你需要在pages目录里补建同名页面或者把app.json中注册的页面删减到实际存在的页面。很多来路不明的源码包在打包上传时漏了文件先跑通这一步比急着改业务逻辑更重要。// app.js 中的常见配置示例 App({ globalData: { // 改成你自己的 Discuz 站点地址不要带结尾斜杠 apiBaseUrl: https://bbs.example.com, // 用户登录后的会话标识后续所有请求头都会带上 sessionCookie: }, onLaunch() { // 启动时自动检查本地是否有缓存的登录态 const cookie wx.getStorageSync(sessionCookie); if (cookie) { this.globalData.sessionCookie cookie; } } })这段代码的逻辑是把站点地址统一收敛到globalData.apiBaseUrl后续所有网络请求都从这个字段读取避免每个页面各写各的域名后期换域名时只改一处。sessionCookie字段专门存放登录后的身份凭证小程序冷启动时从本地缓存恢复避免了每次打开都要重新登录的尴尬。参数说明apiBaseUrl的格式必须是https://域名这种完整协议头格式不能写成bbs.example.com这种裸域名否则请求会直接失败sessionCookie的取值在第四章节登录流程中会具体说明。3.2 改出第一屏能看的列表页forumindex 接口与分页参数导入工程后默认首页通常是帖子列表。如果编译后首页是一片空白多半是接口地址不对。找一个能正常浏览帖子的 Discuz! 站点在浏览器里访问它的 API 地址确认返回格式。常见接口返回格式有两种一种是直接返回 JSON 数组另一种是包了一层{code, data}。你需要根据实际返回结构去调整pages/index/index.js里的数据处理逻辑。这里有一个实用的调试思路把接口 URL 里的参数抄下来直接在微信开发者工具里打开调试器在 Console 里用wx.request去请求一次看看返回值里有没有帖子标题。先用最小请求打通数据链路再谈页面渲染。分页参数在 Discuz! 接口里通常叫page和perpage第一页请求下发page1perpage20下拉加载更多时递增page。这里有一个常见错误源码包默认每页取 10 条在桌面端浏览没问题但小程序屏幕小、信息密度低10 条会让用户觉得内容太少下拉刷新频率过高。我一般会改成 15 到 20 条同时给列表页加上节流防止用户快速下拉时连续发出多个请求Discuz! 的 MySQL 扛不住高频查询时页面会直接卡死。// pages/index/index.js 中加载帖子列表的核心请求 loadThreads(page) { wx.request({ url: ${getApp().globalData.apiBaseUrl}/api.php?modforumdisplay, data: { forum: this.data.currentForumId, // 版块 ID-1 表示全部版块 page: page, perpage: 20, // 每页条数调整到 15-20 比较合理 }, header: { Content-Type: application/json, Cookie: getApp().globalData.sessionCookie // 带上登录态 }, success: (res) { if (res.statusCode 200 res.data.code 0) { this.setData({ threadList: page 1 ? res.data.data : this.data.threadList.concat(res.data.data), page: page }); } else { console.error(接口返回错误, res.data); } }, fail: (err) { console.error(网络请求失败, err); } }); }逻辑上loadThreads接收页码参数请求forumdisplay接口获取帖子列表。如果传page1就直接覆盖列表否则把新数据追加到已有列表后面这是微信小程序列表页的标准写法。header 里带上 Cookie 是为了保留登录状态如果你还没接登录流程这里可以先传空字符串。参数说明forum字段为 -1 时拉取全站最新帖子适合做首页信息流指定数字时只拉某版块帖子适合后续做版块切换perpage不建议超过 20Discuz! 单页查询大于 20 条时 MySQL 扫描的行数会明显增加论坛帖子量过 10 万后会有明显的延迟感。请求失败时打了console.error这一步不是多余代码——真机调试时你看不到网络面板控制台是你唯一的排错入口。4. 对接 Discuz! 账号体系微信登录、发帖回帖与获取手机号4.1 微信登录换取论坛 uidcode2session 与本地 session 的映射小程序端的登录流程和传统网页完全不同核心区别在于拿不到 Discuz! 传统的用户名密码表单而是通过微信的wx.login拿到临时 code后端拿着 code 去微信服务器换 openid再把 openid 和 Discuz! 用户表做映射。源码包里通常会在后端提供login.php之类的接口流程一般是小程序端wx.login拿到 codePOST 给后端后端去https://api.weixin.qq.com/sns/jscode2session换取 openid然后拿着 openid 查 Discuz! 的common_member表如果查不到就自动创建一个新用户最后后端生成一个会话标识返回给小程序端。这里有一个坑Discuz! 的 uid 是整数自增主键而 openid 是一长串字符串。如果后端每次登录都查 openid 是否已存在这个逻辑没问题但很多源码包偷懒直接把 openid 截一段当用户名填充到 Discuz! 用户表导致论坛后台出现一堆乱码用户名。正确做法是建一张映射表至少存三个字段openid、uid、last_login_time登录时先查映射表有记录就直接返回 uid没有记录才去注册新用户。这一张表是论坛数据统计的根基没有它你后面做绑定手机号、用户禁言都无从下手。// 小程序端登录入口的通用写法 login() { wx.login({ success: (res) { if (res.code) { wx.request({ url: ${getApp().globalData.apiBaseUrl}/api.php?modlogin, method: POST, data: { code: res.code }, success: (rsp) { if (rsp.data.code 0) { const sessionCookie rsp.data.data.sessionid; getApp().globalData.sessionCookie sessionCookie; wx.setStorageSync(sessionCookie, sessionCookie); wx.setStorageSync(uid, rsp.data.data.uid); } else { wx.showToast({ title: 登录失败, icon: none }); } } }); } } }); }代码逻辑是wx.login拿到微信临时凭证 code传给后端登录接口后端校验后返回自定义会话 ID小程序端存到全局变量和 Storage 里。这个会话 ID 本质上是你后端自己生成的一个随机字符串可以理解为小程序版“cookie”。参数说明modlogin是 API 网关里的登录业务标识如果源码包里不是这个名字请以实际包里的参数为准后端返回的sessionid必须是由后端生成的随机串不能直接返回 openid否则等于把微信用户标识暴露给客户端任何拿到这个值的人都能伪装成该用户wx.setStorageSync做的是本地持久化不调用会面临每次启动都掉登录态的问题。4.2 获取手机号的现成写法button open-type 与 code 换取手机号如果你确实需要绑定手机号微信官方推荐的方式早就不是直接把手机号明文返回给开发者了。现在正确的流程是页面上放一个button open-typegetPhoneNumber按钮用户点击后微信弹出授权框用户同意后bindgetphonenumber事件会回调拿到一个code把这个code传到后端后端再用这个 code 去微信接口换取真实的手机号。注意这个 code 一次有效有效期只有五分钟而且只能使用一次。!-- 页面中的按钮写法 -- button open-typegetPhoneNumber bindgetphonenumberonPhoneNumber微信绑定手机号/button// 处理手机号授权回调 onPhoneNumber(e) { if (e.detail.code) { wx.request({ url: ${getApp().globalData.apiBaseUrl}/api.php?modbindphone, method: POST, data: { code: e.detail.code }, success: (res) { if (res.data.code 0) { wx.showToast({ title: 绑定成功, icon: success }); } else { wx.showToast({ title: res.data.msg || 绑定失败, icon: none }); } } }); } else { wx.showToast({ title: 你取消了授权, icon: none }); } }逻辑是用户点击按钮触发bindgetphonenumber事件对象e.detail.code里就是后端需要的凭证后端拿凭证换手机号绑定到 Discuz! 用户表。这个方案的代价是每次调用会扣短信费用而且个人主体小程序开通该能力时需要提交额外审核材料。一个现实判断如果你的论坛没有强实名需求这一步可以不接只做微信登录就够用了做了反而增加审核风险——微信会对虚拟支付、金融类目严格把关一个社区论坛接入手机号收集能力类目不匹配时会被打回。真到需要手机号那一天先把主体资质和类目搞清楚了再动手。4.3 发帖与回帖的鉴权formhash 与 cookie 的坑Discuz! 的发帖机制里有一个防 CSRF 的字段叫 formhash它本质上是和当前用户会话绑定的一个随机哈希值。Web 端发帖时这个值直接从页面上取就行但小程序端不能这样做——你需要先在登录时从接口里同步获取当前用户的 formhash并把它缓存下来发帖时再带上。有不少源码包把 formhash 硬编码在配置里这在单用户调试时看不出来问题但只要有两个以上账号同时在线就会出现“发帖提示来路不正确”的诡异现象原因就是 formhash 和 cookie 不匹配。常见做法是登录接口除了返回 sessionid再返回一个formhash字段小程序端存到 globalData 里。发帖请求要同时带上 Cookie 头和 formhash 参数两者缺一不可。Discuz! 对合规请求的校验顺序是先查 cookie 里的登录态再比对 formhash 是否与会话匹配两步都过了才允许写库。如果你部署后发现能浏览不能发帖优先检查这两样东西有没有正确传过去。// 发帖接口的请求封装 postThread(title, content, fid) { wx.request({ url: ${getApp().globalData.apiBaseUrl}/api.php?modnewthread, method: POST, header: { Cookie: getApp().globalData.sessionCookie, }, data: { fid: fid, subject: title, message: content, formhash: getApp().globalData.formhash // 登录时缓存的哈希值 }, success: (res) { if (res.data.code 0) { wx.showToast({ title: 发布成功, icon: success }); } else { wx.showToast({ title: res.data.msg, icon: none }); } } }); }值得留意的是header和data的位置Cookie 放在请求头里formhash 放在请求体里。很多新手把 formhash 也放进 header导致后端取不到值报“请求数据不完整”。参数说明fid是版块 ID发帖前需要先让用户选择要发到哪个版块一般通过版块列表接口拿subject和message分别对应标题和正文Discuz! 对标题长度有限制通常 80 字以内前端需要做截断校验否则后端会直接丢弃超长部分formhash 必须与当前 sessionid 配套使用。另一个细节是 Discuz! 的发帖频率限制——比如 60 秒内只能发一帖——小程序端最好在点击发布后把按钮置灰等接口返回后再恢复防止用户连点造成重复发帖。5. 避坑Discuz! 小程序最常见的 5 个翻车现场5.1 白屏加请求失败HTTP 与 HTTPS 混用现象开发工具里一切正常手机预览全部白屏控制台报request:fail。原因部署机只挂了 HTTP 证书小程序端请求地址却以https://开头或者反过来。更常见的是apiBaseUrl写的http://但微信小程序对正式版强制要求 HTTPS。解决把 Discuz! 站点全部切到 HTTPS尤其是接口地址必须和页面地址同协议。我之前犯过的错是Discuz! 后台功能正常就只给首页挂了证书结果小程序请求接口时证书校验失败排查了很久才发现是 Nginx 配置里漏了location /api.php的 SSL 模块。所以你改完证书后别急着真机预览先在浏览器里用 HTTPS 访问一遍所有用到的接口路径看看有没有证书报错。5.2 登录态经常掉Session 有效期与小程序冷启动现象用户用得好好的隔几个小时打开小程序就变成未登录状态需要重新授权。原因Discuz! 的 Web 登录态存在 cookie 里cookie 有有效期通常默认是 7 天而小程序的冷启动会让sessionCookie从 Storage 恢复如果后端在 session 表里清掉了过期记录前端恢复的 cookie 就是一张废票。解决不要只用wx.setStorageSync存 cookie还要存一份登录时间戳每次启动时判断是否超过有效期如果过期就静默掉用wx.login重新登录。更稳妥的方案是后端写一份“记住登录”的逻辑把小程序的登录态有效期拉长到 30 天但要注意安全边界别把管理员账号也做成永久会话。5.3 列表页内容一直空白接口返回被 Discuz! 的 SEO 设置拦截现象fetch 接口返回 200data却是空数组或 HTML 字符串。原因Discuz! 后台开启了伪静态或列表页 SEO 设置导致原本的forumdisplay接口被 Rewrite 规则拦截直接重写到了静态页面。解决先去 Discuz! 后台看看“全局 → SEO 设置”里的 URL 静态化选项把 API 请求的路径排除在伪静态之外或者在 Nginx 里加一条 location 优先匹配。这类问题在改过伪静态规则的站点上特别常见排查时最直接的方式是把接口 URL 复制到浏览器里看返回值如果看到的是 HTML 页面而不是 JSON那基本就是重写规则的锅。5.4 帖子里的图片全部裂掉Discuz! 附件防盗链现象帖子列表正常帖子详情里的图片全部显示不出来浏览器打开图片 URL 却能看。原因Discuz! 后台开启了远程附件防盗链校验了 Referer 头。小程序发请求时默认不带 Referer后端就当成了盗链请求拒绝掉。解决在 Discuz! 后台关闭附件防盗链或者在后端接口里对小程序请求做 Referer 白名单校验。这里提醒一句如果你论坛有大量外部图片外链图片裂掉还有可能是外链域名被微信白名单卡了——小程序里所有image标签加载的图片域名必须加入 downloadFile 合法域名列表否则图片照样出不来。5.5 页面卡顿到没法用setData 塞进了一整屏帖子数据现象滚动列表时明显掉帧安卓机型尤其严重。原因小程序是数据驱动视图每次setData都会把数据从逻辑层传到渲染层如果你一次性把整个帖子列表的 HTML 片段往 setData 里塞传输耗时会成倍上升。解决列表数据只保留渲染必要的字段比如 tid、title、author、replies、timestamp其他一概过滤掉分页加载时只 append 新数据不要每次重新 setData 整个数组。我在一个项目里遇到类似的问题把每页数据从 40 条降到 15 条同时用虚拟列表的思路只渲染当前视口内的帖子条目后滑动流畅度直接上了一个台阶。这条对于老旧手机用户占比高的论坛来说体验差异不是一点点。6. 把 Discuz! 小程序做成能上线的状态验证清单与一个必改项6.1 上线前的完整验证清单小程序不是写完就能交付的。按我的习惯上线前至少过一遍下面这张表第一在开发者工具里用“真机调试”跑一遍核心流程——游客浏览、微信登录、发帖、回帖、下拉刷新每个流程都要顺手测试断网和弱网场景第二确认所有请求域名都配置到了小程序后台的 request 合法域名图片域名配到 downloadFile 合法域名第三确认站点已备案且备案主体与小程序主体一致不一致的情况在审核时会收到“域名主体不一致”的驳回第四把 Discuz! 后台的验证码设置调整为非必填不然小程序发帖时没有验证码输入框用户会被卡住第五检查小程序隐私弹窗——微信要求涉及收集用户信息时必须有隐私保护指引Discuz! 小程序的登录接口会收集微信昵称和头像要在后台填写这份指引并关联版本否则有被下架风险。6.2 一个必改项把登录解密换成标准 code 换取流程如果说整个源码包里只能挑一处必须更新那就是微信登录换取用户信息的逻辑。早期版本的源码包往往用wx.getUserInfo或wx.getUserProfile拿用户信息或者干脆让后端用session_key解密手机号数据。微信官方早就把这些旧接口收紧了新版本小程序更不应该逆势而上。我现在做 Discuz! 小程序的标准做法是登录只用wx.login换 code后端拿 code 换 openid 和 unionid用户昵称和头像靠button open-typechooseAvatar和昵称输入框让用户主动填写如果界面想省事至少也要用基础库 2.21.2 之后支持的getPhoneCode写法获取手机号旧接口一律不碰。最后说一个坐标系供你参考一个 Discuz! 论坛小程序从拿到 zip 包到真正推上线顺畅的话需要 3 到 5 天其中域名备案等待是硬等待不顺畅的话主要耗在登录和发帖的鉴权排错上。当年我帮朋友的一个站点部署前后折腾了接近两周最后问题落在一个不起眼的点上——Discuz! 后台开启了防灌水“发帖需要验证问答”小程序端没有问答框所有发帖请求都被拒了。所以你在排错时如果碰到诡异的“明明逻辑没问题就是不行”先去 Discuz! 后台翻一遍所有安全设置项那些为 Web 端设计的校验只要存在就会成为小程序的隐形路障。这套方向是值投入的Discuz! 的用户系统、帖子数据、管理后台都是现成的小程序只做交互层比从零做原生社区轻太多希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?