ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

微信小程序+ThinkPHP6商城实战:登录态、JWT鉴权与Swoole优化

微信小程序+ThinkPHP6商城实战:登录态、JWT鉴权与Swoole优化 简介这是一套开箱即用的微信小程序商城全栈解决方案面向前端与PHP后端初学者、小型电商项目开发者及教学实践者解决从零搭建可运行商城系统的技术门槛问题。资源包含微信小程序前台商品展示、购物车、订单全流程、ThinkPHP构建的完整后台商品/订单/用户管理及详细部署文档覆盖开发、配置、上线全环节。压缩包共2001个文件以629个PHP文件后端逻辑与API、438个HTML/309个JS/89个CSS文件小程序视图与交互、311个GIF/21个PNG/17个JPG界面素材为主辅以SQL数据库脚本、配置文件与README说明总大小44.4MB结构清晰、模块分离度高。已有533人学习下载读者可直接获取可调试的前后端源码、环境搭建指南、接口调用说明及常见部署问题排查提示快速复现并二次开发属于自己的轻量级微信商城系统。1. 这不是“拿来就能跑”的商城源码而是一套能让你真正搞懂微信小程序ThinkPHP协同逻辑的实战工程包你下载过几十个“微信小程序商城源码”解压打开project.config.json就报错、app.js里一堆wx.request指向http://localhost:8080、后端index.php一运行就提示Class think\App not found——这不是你手残是绝大多数所谓“完整版”源码根本没经过真实环境验证。这套「简易商城微信小程序源码 ThinkPHP后端完整版 搭建教程」不一样它来自一个已上线运营3个月、日均订单200的本地生活服务项目剥离出的最小可行闭环MVP前端用原生小程序框架非uniapp后端基于 ThinkPHP 6.1 LTS 版本构建所有接口路径、token校验、登录态透传、支付回调地址全部按微信开放平台最新规范2024年Q2对齐。它不追求炫酷UI但每一步都经得起console.log和curl -v推敲它不塞满营销插件但把「用户授权 → 手机号绑定 → 商品列表 → 下单 → 支付回调 → 订单状态同步」这条主链路拆成了可调试、可打断、可打桩的原子模块。适合两类人一是刚学完小程序基础、卡在“怎么连后端”上的开发者二是需要快速验证业务模型、拒绝被“伪完整源码”浪费三天部署时间的创业者。2. 前端小程序从app.js入口开始理清登录态与请求拦截的真实链路2.1 登录态管理为什么wx.login()后必须走code2Session且不能跳过encryptedData解密小程序端登录不是简单调wx.login()拿 code 就完事。本工程强制要求用户点击“授权手机号”按钮时先触发wx.getPhoneNumber({ withCredentials: true })获取encryptedDataiv同时在app.js的onLaunch中已预埋wx.login()获取临时 code二者通过wx.request()同步发往后端/api/v1/login接口code 必须和 encryptedData/iv 成对提交否则后端无法完成微信服务器auth.code2Sessiondecrypt双校验。// app.js 中关键逻辑已精简 App({ globalData: { token: , // 存储后端签发的 JWT token非微信 session_key userInfo: null }, onLaunch() { // 1. 静默获取 code不弹窗 wx.login({ success: res { this.globalData.code res.code; // 临时存储供后续提交 } }); }, // 2. 用户主动授权手机号时触发 bindGetPhoneNumber(e) { if (e.detail.encryptedData) { // 3. 将 code encryptedData iv 一次性 POST 给后端 wx.request({ url: https://your-domain.com/api/v1/login, method: POST, data: { code: this.globalData.code, encryptedData: e.detail.encryptedData, iv: e.detail.iv }, success: res { if (res.data.code 200) { this.globalData.token res.data.data.token; // 关键存的是后端 JWT wx.switchTab({ url: /pages/index/index }); } } }); } } });提示this.globalData.code是临时缓存实际生产中建议用wx.setStorageSync持久化并加时效5分钟避免用户授权延迟导致 code 过期微信规定 code 5分钟失效。本工程未做持久化是为降低新手理解门槛但你在部署时务必补上。2.2 请求拦截如何用interceptors统一注入 token 并处理 401 跳转小程序没有 axios但可以用wx.request封装拦截器。本工程在utils/request.js中实现// utils/request.js function request(options) { const token getApp().globalData.token; const header { Content-Type: application/json, ...options.header }; if (token) { header.Authorization Bearer ${token}; // 注意不是 token xxx } return new Promise((resolve, reject) { wx.request({ ...options, header, success: res { // 统一错误处理401 强制跳转登录页 if (res.statusCode 401) { wx.navigateTo({ url: /pages/auth/login }); reject(new Error(登录态失效)); return; } if (res.data.code ! 200) { wx.showToast({ title: res.data.msg || 请求失败, icon: none }); reject(res.data); return; } resolve(res.data); }, fail: err { wx.showToast({ title: 网络错误, icon: none }); reject(err); } }); }); } // 导出封装后的 request export default request;参数说明Authorization: Bearer ${token}是本工程后端ThinkPHP JWT 验证中间件唯一接受的认证头格式硬编码写死res.data.code ! 200判断依据来自后端统一响应结构{ code: 200, msg: success, data: {...} }前端所有页面调用request({url: /api/goods/list})即可无需重复写if (res.data.code)wx.navigateTo而非wx.redirectTo保留返回栈用户登录后点返回可回到商品页——这是真实用户体验细节很多源码直接redirectTo导致用户迷路。2.3 商品列表页如何用分页 缓存规避小程序“白屏闪动”小程序 setData 频繁触发会导致页面重绘卡顿。本工程在pages/goods/list.js中采用“内存缓存 分页标记”双策略Page({ data: { goodsList: [], page: 1, pageSize: 10, hasMore: true, loading: false }, onLoad() { this.loadGoods(); }, loadGoods() { if (this.data.loading || !this.data.hasMore) return; this.setData({ loading: true }); request({ url: /api/v1/goods, data: { page: this.data.page, size: this.data.pageSize } }).then(res { const newList this.data.goodsList.concat(res.data.list); this.setData({ goodsList: newList, page: this.data.page 1, hasMore: res.data.list.length this.data.pageSize, loading: false }); }); }, onReachBottom() { this.loadGoods(); } });关键设计点hasMore控制是否继续加载避免无意义请求后端返回list.length pageSize即置falsegoodsList用concat而非push保证数组引用变更触发视图更新onReachBottom触发时先校验loading和hasMore防止快速滑动多次触发重复请求——这是真实场景下最常翻车的点。3. ThinkPHP 后端从composer install到nginx.conf跑通最小依赖闭环3.1 环境检查为什么 PHP 8.1 和 PDO_MySQL 是硬性门槛本工程后端基于 ThinkPHP 6.1.12LTS 最新版明确要求 PHP ≥ 8.1。原因有三TP6.1 使用了 PHP 8.1 的enum类型声明如app/common/enum/OrderStatus.phpJWT 验证库firebase/php-jwtv6.10 强制要求 PHP 8.1MySQL 8.0 默认启用caching_sha2_password认证插件PHP 8.0 的 PDO 才原生支持。执行前请确认# 检查 PHP 版本及扩展 php -v # 必须 ≥ 8.1 php -m | grep pdo_mysql # 必须存在 php -m | grep openssl # JWT 加密必需注意如果你用宝塔面板或 Docker务必选择php:8.1-apache或php:8.1-fpm镜像php:7.4或php:8.0会直接报ParseError: syntax error, unexpected token enum。3.2 安装流程composer install后必须手动执行的三步初始化解压thinkphp-backend.zip后进入根目录执行# 1. 安装依赖国内源加速 composer install --repositoryhttps://packagist.phpcomposer.com # 2. 生成 runtime 目录并赋权TP6 必须 mkdir -p runtime/log runtime/cache runtime/session runtime/view chmod -R 755 runtime/ # 3. 复制环境配置并修改数据库信息 cp .env.example .env nano .env # 修改 DB_HOST、DB_PORT、DB_NAME、DB_USER、DB_PASS.env关键配置项说明配置项示例值说明APP_DEBUGtrue开发时设为 true上线必须false否则暴露敏感路径JWT_SECRETyour_32_char_secret_key_here必须修改生成命令openssl rand -base64 32WECHAT_APPID/WECHAT_APPSECRETwx1234567890...微信公众平台 → 开发管理 → 基本配置 获取ALIPAY_APPID2021000123456789支付宝开放平台 → 应用管理 → 查看应用公钥3.3 Nginx 配置为什么location /必须指向public/且禁用.env访问ThinkPHP 6 推荐将 Web 入口放在public/目录index.php是唯一入口。Nginx 配置核心段server { listen 80; server_name your-domain.com; root /path/to/thinkphp-backend/public; # 关键root 指向 public/ index index.php; location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; # 或 unix:/var/run/php/php8.1-fpm.sock fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } # 严格禁止访问敏感文件 location ~ /\.(env|log|ini|conf|sh|bash)$ { deny all; } }血泪经验曾见某源码把root指向项目根目录导致.env文件被直接curl http://domain.com/.env下载数据库密码全泄露。本工程public/index.php开头有define(APP_PATH, __DIR__ . /../app/);确保应用逻辑层与 Web 层物理隔离。4. 前后端联调打通wx.request到think\Controller的全链路验证4.1 接口调试用curl模拟小程序请求绕过前端快速定位问题当小程序页面空白、控制台无报错时优先用curl直接测后端接口排除前端干扰# 测试登录接口需先用微信开发者工具获取真实 encryptedData curl -X POST https://your-domain.com/api/v1/login \ -H Content-Type: application/json \ -d { code: 0.qJZa1YbC0fD3E4G5H6I7J8K9L0M1N2O3, encryptedData: kFj...long_base64_string..., iv: aBcDeFgHiJkLmNoPqRsTuVwXyZ012345 }预期响应{ code: 200, msg: 登录成功, data: { token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..., user_id: 123, nickname: 张三 } }若返回{code:500,msg:解密失败}说明WECHAT_APPID/WECHAT_APPSECRET配置错误或encryptedData/iv已过期微信规定 5分钟内有效或后端app/service/WxService.php中decryptData()方法未正确处理 PKCS#7 填充。4.2 数据库初始化migration与seed的执行顺序不能颠倒本工程使用 ThinkPHP 原生迁移功能必须按顺序执行# 1. 执行迁移创建表结构 php think migrate:run # 2. 执行种子填充基础数据管理员账号、商品分类、测试商品 php think seed:run # 3. 验证数据 mysql -u root -p -e SELECT id,username FROM tp_admin LIMIT 1; your_db_name # 应返回1 | admin避坑清单现象原因解决php think migrate:run报错Class think\migration\Command not found未安装topthink/think-migration扩展执行composer require topthink/think-migration补装扩展后重试php think seed:run提示Table tp_goods doesnt exist迁移未成功执行先php think migrate:status查看状态再php think migrate:reset回滚后重跑严禁跳过迁移直接 seed登录后台http://your-domain.com/admin显示 404Nginxroot指向错误或public/admin.php不存在本工程后台入口是public/index.php?sadmin检查路由配置后台 URL 应为https://your-domain.com/index.php?sadmin4.3 支付回调为什么notify_url必须是公网可访问且带 HTTPS微信支付回调地址notify_url在app/config/alipay.php和app/config/wechat.php中配置必须满足域名已备案国内服务器强制要求使用 HTTPS微信校验证书能被微信服务器直连不能是localhost、127.0.0.1或内网 IP返回return [return_code SUCCESS, return_msg OK]且 HTTP 状态码 200。测试技巧用ngrok临时映射本地端口仅开发用# 本地启动 PHP 内置服务器 php -S 0.0.0.0:8000 -t public/ # 启动 ngrok需注册获取 authtoken ngrok http 8000 # 输出类似Forwarding https://abc123.ngrok.io - http://localhost:8000 # 将 https://abc123.ngrok.io/api/v1/pay/notify 填入微信商户平台玄学提醒微信回调有时会重试多次后端app/controller/api/PayController.php的notify()方法开头必须加幂等判断如查order_no是否已支付成功否则同一笔订单可能被扣款两次。5. 避坑指南这六个高频翻车点90% 的人至少踩过三个5.1 小程序request报net::ERR_CONNECTION_REFUSED不是后端没起而是域名未配置现象小程序控制台报net::ERR_CONNECTION_REFUSED但curl https://your-domain.com/api/v1/goods正常返回。原因微信小程序强制要求所有wx.request域名必须在「微信公众平台 → 开发管理 → 开发设置 → 服务器域名」中备案且只支持 HTTPS。http://localhost、http://192.168.1.100、甚至http://your-domain.comHTTP全被拦截。解决登录 mp.weixin.qq.com 进入「开发管理」→「开发设置」在「request 合法域名」中添加你的域名如https://your-domain.com必须带 https:// 前缀保存后等待 5 分钟生效微信缓存期间重启开发者工具若用二级域名如api.your-domain.com需单独添加主域名不自动继承。5.2 ThinkPHP 报Class think\App not foundComposer 自动加载失效的三种可能现象浏览器访问https://your-domain.com显示Fatal error: Uncaught Error: Class think\App not found。原因vendor/autoload.php未被public/index.php正确引入检查require __DIR__./../vendor/autoload.php;是否存在composer install未成功执行vendor/目录为空或缺失topthink/framework服务器 PHP 运行用户如www-data对vendor/目录无读取权限。解决进入项目根目录执行ls -la vendor/topthink/确认存在framework目录执行php -f public/index.php看是否报相同错误排除 Web 服务器配置问题sudo chown -R www-data:www-data vendor/Ubuntu或sudo chown -R nginx:nginx vendor/CentOS。5.3 商品图片显示 404路径别名static未在config/app.php中定义现象小程序商品列表图片全显示灰色占位图Network 面板看到GET https://your-domain.com/static/images/goods/1.jpg 404。原因ThinkPHP 6 的静态资源默认放在public/static/但控制器中用Url::build(static/images/xxx.jpg)生成 URL 时static别名未在config/app.php中配置。解决打开config/app.php找到view_replace_str配置项添加__STATIC__ /static注意是双下划线在模板中用{:url(static/images/xxx.jpg)}或{$request-root()}static/images/xxx.jpg替代硬编码路径。5.4 登录后getApp().globalData.token为空小程序onLaunch和onShow的执行时机陷阱现象用户授权手机号后跳转首页但首页request仍报 401console.log(getApp().globalData.token)为。原因onLaunch只在小程序冷启动时执行一次而用户授权后热启动如从聊天窗口点击链接进入onLaunch不会再次触发globalData.code为空。解决在app.js的onShow中补充 code 获取逻辑onShow() { // 热启动时重新获取 code if (!this.globalData.code) { wx.login({ success: res this.globalData.code res.code }); } },或更稳妥方案授权成功后立即将token存入wx.setStorageSync(token)全局getApp()时从 storage 读取。5.5 支付回调收不到通知微信服务器无法访问你的notify_url现象用户支付成功小程序端一直显示“支付中”后台订单状态不变。原因notify_url域名未备案或未开启 HTTPS服务器防火墙如ufw或安全组屏蔽了 443 端口Nginx 配置中location /api/v1/pay/notify未正确代理到 PHP-FPM。排查用curl -v https://your-domain.com/api/v1/pay/notify看是否返回 200查看 Nginx 错误日志tail -f /var/log/nginx/error.log微信商户平台 → 「开发配置」→ 「APIv3密钥」→ 「查看回调地址」点击「测试」按钮微信会发送模拟回调观察你的服务器日志是否有记录。6. 进阶技巧用think-swoole将并发能力提升 3 倍同时保持代码零改造6.1 为什么原生 PHP-FPM 在高并发下单页加载慢瓶颈在哪当你用ab -n 1000 -c 100 https://your-domain.com/api/v1/goods测试时平均响应时间超过 800msTPS每秒事务数低于 30。根本原因在于PHP-FPM 是进程/线程模型每个请求独占一个 worker 进程MySQL 连接池未复用每次Db::table()-select()都新建连接vendor/autoload.php的 PSR-4 自动加载耗时尤其app/下类多时session_start()阻塞文件存储默认锁表。这些瓶颈在 ThinkPHP 6.1 Swoole 4.8 下可被彻底绕过。6.2 零代码改造接入think-swoole三步启用协程 HTTP 服务器本工程已预留think-swoole支持只需三步步骤 1安装扩展# Ubuntu/Debian sudo apt install php-dev gcc make pecl install swoole echo extensionswoole.so | sudo tee /etc/php/8.1/mods-available/swoole.ini sudo phpenmod -v 8.1 swoole步骤 2安装 ThinkPHP Swoole 扩展cd /path/to/thinkphp-backend composer require topthink/think-swoole步骤 3启动 Swoole 服务# 启动监听 9501 端口 php think swoole # 查看状态 php think swoole:status # 停止 php think swoole:stop此时访问http://your-server-ip:9501/api/v1/goods即为 Swoole 服务性能对比实测场景PHP-FPM (8.1)Swoole (4.8)提升并发 10032 TPS, 920ms avg98 TPS, 310ms avg3.1×并发 50041 TPS, 1200ms avg125 TPS, 400ms avg3.0×内存占用120MB (100 workers)45MB (1 master 4 worker)↓62%关键参数说明config/swoole.phpreturn [ server [ host 0.0.0.0, port 9501, type http, // HTTP 协议非 WebSocket process_type all, // 启用所有协程组件 option [ worker_num 4, // 根据 CPU 核数设4核机器设4 max_request 3000, // worker 处理 3000 请求后自动重启防内存泄漏 task_worker_num 2, // 异步任务进程数用于发短信、写日志等 ], ], coroutine [ db true, // 开启协程 MySQL自动复用连接 redis true, // 若用 Redis 缓存同样协程化 ], ];6.3 小程序端无缝切换用 Nginx 反向代理隐藏端口差异用户不可能访问:9501端口需用 Nginx 将https://your-domain.com流量代理到 Swooleupstream swoole_backend { server 127.0.0.1:9501; } server { listen 443 ssl; server_name your-domain.com; # ... SSL 配置省略 ... location / { proxy_pass http://swoole_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; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; } }验证是否生效重启 Nginxsudo systemctl restart nginx查看 Swoole 进程ps aux | grep swoole访问https://your-domain.com/api/v1/goods响应头中应含Server: swoole-http-server。从那以后我每次上线新项目都强制走一遍「PHP-FPM 基准测试 → Swoole 接入 → Nginx 代理验证」三步流程。不是为了炫技而是因为真实用户不会容忍 1 秒以上的首屏等待——尤其当他们正用手机在地铁里刷商城时。这套源码的价值不在于它多完美而在于它把所有坑都摊开给你看让你在第一次部署时就避开 90% 的深夜救火。希望帮到你。本文还有配套的精品资源点击获取
返回列表