Laravel+微信小程序手办商城源码:前后端打通与部署实战
兄弟们手办这坑我是踩得明明白白。前阵子为了找一套能跑的商城源码翻遍了各大论坛和代码仓库要么是纯前端写死的假数据要么后端接口烂得跟蜘蛛网一样。后来索性自己动手用 Laravel 撸了一套“玩转潮玩”手办小程序前后端全部打通从商品展示到下单支付流程完整。文章末尾有获取方式觉得有用的可以先点个关注后续我还会持续迭代这套代码分享更多实战改造过程。那段时间我几乎把热词榜翻了个遍——“小程序抓包”、“charles使用教程”、“小程序商城”、“源码建站”这些词反复出现看得出来太多人卡在前后端联调这一步了。这套程序刚好把小程序端和 Laravel 后端 API 完整做通了数据结构、接口字段、状态码我都按实际生产环境的标准来设计拿来即用也方便二次开发。不管你是想做个副业项目接单还是拿来练手学习小程序全栈开发这套源码都能少走很多弯路。1. 项目整体设计与技术选型思路先说技术栈后端选择 Laravel 这个框架老实说是权衡之后的结果。市面上开源商城系统不少Java 的若依、Python 的 Django 商城也有但 PHP 生态在小程序后端这块有天然优势——部署简单、上手门槛低、虚拟主机都能跑。而 Laravel 又是 PHP 框架里最像“现代框架”的那个ORM、中间件、队列、路由模型绑定都是现成的开发效率确实比其他老牌框架高很多。试想一下你用 ThinkPHP 写个接口得手动拼 SQL、手动做参数校验Laravel 里写个 FormRequest 就搞定了这对小团队和个人开发者来说省下的时间不是一点半点。小程序端选微信原生框架而不是 uni-app主要考虑是减少一层抽象。uni-app 确实能一套代码多端跑但编译层偶尔会出一些莫名其妙的兼容问题排查起来特别折磨人。微信原生框架写的代码逻辑最直白遇到问题社区资料也多毕竟做小程序开发绕不开微信这个平台原生语法学扎实了以后去哪个团队都不慌。整个项目的模块划分是这样的用户端小程序首页推荐、分类浏览、商品详情、购物车、订单管理、个人中心、收货地址管理管理后台预留接口商品管理、订单管理、用户管理、轮播图配置后端 API 服务Laravel 提供 RESTful 接口统一返回 JSON 格式数据。关于数据库设计我花了不少心思。商品表products和商品图片表product_images分开存这样商品列表页加载缩略图时不用把详情大图也一块查出来性能上的差异在数据量大了以后会非常明显。订单表orders和订单明细表order_items是标准的主从表关系下单时把商品快照信息冗余进明细表里这样即使以后商品改名或者下架用户的历史订单依然能正确显示。2. 核心功能模块与数据库设计2.1 用户登录与鉴权机制小程序端用户登录不能用传统的账号密码必须走微信的 code 换 session_key 流程。这里我踩过坑一开始直接拿前端传过来的 code 去调微信接口后来发现问题在于 code 一次性有效而且有效期只有五分钟。正确的做法是前端调用wx.login()拿到 code传给后端后端再用 code 去微信服务器换 openid 和 session_key然后用自己的机制生成一个 token 返回给前端。整个流程我用一张表来理清步骤前端操作后端处理1wx.login() 获取 code接收 code2请求 /api/auth/login用 code 调微信接口获取 openid3接收 token 并存到 storage查找用户不存在则自动注册4后续请求头带上 token中间件校验 token 有效性后端我用了 Laravel Sanctum 来做 API 鉴权这个扩展比 JWT 好用数据库表都不用自己建执行一下迁移命令就自动生成 personal_access_tokens 表。每次请求带上 Bearer Token中间件一拦后面所有接口都能通过$request-user()拿到当前登录用户代码写起来非常舒服。2.2 商品模块与分类筛选商品列表和详情是最核心的展示模块直接决定用户的第一印象。列表页我设计了两种加载模式首页推荐流和分类页列表。推荐流就是按创建时间倒序取最新的商品配合分页参数用cursor方式翻页分类列表则支持按价格、销量、上架时间排序。查询参数的设计可以参考本地// app/Http/Controllers/Api/ProductController.php public function index(Request $request) { $query Product::query()-where(status, 1); if ($categoryId $request-input(category_id)) { $query-where(category_id, $categoryId); } $sort $request-input(sort, latest); switch ($sort) { case sales: $query-orderByDesc(sales_count); break; case price_asc: $query-orderBy(price); break; case price_desc: $query-orderByDesc(price); break; default: $query-orderByDesc(created_at); } return $this-success($query-paginate(10)); }商品详情的接口我额外加了两个字段is_favorite和favorite_count。这样前端在详情页能直接猜出用户有没有收藏过这个商品不用额外再发一个请求去查收藏状态省掉了一次网络往返体验明显更顺滑。商品图片我建议单独建表而不是用 JSON 字段存数组原因是 JSON 字段在 MySQL 里做查询排序不够灵活而且有些老版本的 MySQL 对 JSON 支持并不好。单独用一张表每张图一行记录查的时候用where(product_id, $id)-orderBy(sort_order)取出来逻辑清晰还方便将来做图片懒加载。2.3 购物车与订单流程设计购物车这边我把数据存在后端而不是用小程序本地缓存。这样做的考虑是用户如果换了手机或者清掉微信缓存购物车里的商品不会丢对用户来说体验好很多。缺点是每次加购都要发一个请求但说实话购物车的操作频次并不高后端存储完全扛得住。购物车表核心字段就这么几个用户ID、商品ID、SKU ID、数量、勾选状态。这里要注意一个点勾选状态一定要存不然用户在结算页取消勾选某个商品后再次进入购物车页面状态就乱了。订单流程我走的是“预下单 → 确认收货地址 → 提交订单 → 模拟支付 → 支付成功”这条路。考虑到源码分发主要是学习交流用途支付模块不建议直接接微信支付因为个人主体的小程序很难申请到微信支付权限而且涉及到商户号、证书密钥这些敏感信息不适合放到开源代码里。我预留了PaymentService接口注释写得很清楚要接真实支付只需要实现pay()方法就行。生成订单编号的函数值得分享一下直接用uniqid()的做法不太专业并发高一点就会出现重复单号。我用了日期 随机数 用户ID后三位组合的方式$orderNo date(YmdHis) . str_pad(random_int(0, 999999), 6, 0, STR_PAD_LEFT) . substr($userId, -3);这样同一个用户在同一秒内连下多单也不会冲突而且通过单号能直接看出下单时间和用户信息排查问题的时候特别方便。2.4 管理端接口与数据统计管理端我做了最基础的几个接口商品上下架、订单发货、用户列表、销售统计。小程序管理后台我刻意没有做前端页面因为市面上现成的后台管理模板太多了大家拿到源码后可以按自己的喜好接入 vue-element-admin 或者若依前端接口都是现成的。销售统计这边我写了两个方法今日订单数和今日销售额另外再加一个近七天的走势图数据。统计的逻辑其实就是针对订单表的时间字段做条件筛选加上whereDate(created_at, today())Laravel 的查询构造器对这类操作支持得很顺手。榜单相关词里反复出现“小程序动态设置标题”和“微信小程序顶部导航栏高度”这个在我这个项目里也做了处理。用户浏览不同分类时小程序导航栏标题会动态切换这部分逻辑在小程序前端实现代码注释里也有说明。3. 小程序前端核心页面实现3.1 首页与推荐流骨架首页布局参考了目前主流电商小程序的通用模式顶部搜索框、下方轮播图、金刚区图标、瀑布流商品推荐。我这里统一分为模板为首页、分类页、购物车、个人中心四个 Tab底部导航栏在app.json里配置。轮播图数据来自后端的/api/banners接口直接在onLoad生命周期里请求拿到数据后塞入data中。要注意的是请求时一定要处理好加载态不然用户打开小程序看到一片空白会以为死掉了。我加了一个loading参数控制页面渲染状态数据回来之前展示加载动画。首页商品推荐流的实现要点是列表触底加载也就是热词里说的“微信小程序页面列表加载更多”。逻辑是页面滚动到底部时触发onReachBottom方法把当前页码加一再请求一次接口新数据拼接到旧数据后面。为了避免重复数据接口的分页参数我用page和page_size前端记录page每次请求前检查hasMore字段为 false 就不再发起请求了。3.2 商品详情页参数联动详情页是我花心思最多的页面因为它直接关系到转化率。轮播图、价格、标题、销量、收藏按钮、SKU 选择、图文详情、底部操作栏每个模块都要做好。SKU 选择的逻辑很多人一上来就懵其实核心就一句话传入被选中的规格然后从后端查对应的价格和库存。比如一个手办有三个规格普通版、豪华版、典藏版每个版本价格不一样用户点击某个版本就更新展示的价格。这里我把每个版本的库存独立存储避免出现“总库存还有但某个规格已经卖光”的尴尬。加入购物车的接口调用前前端要先做SKU的合法性校验。如果用户没选规格就直接点击“加入购物车”直接弹 toast 提示“请选择规格”这里的判断逻辑必须放在请求之前否则后端就要多做一层防御性校验。不过作为一名严谨的开发者后端的校验我照样写了一遍两层保险。3.3 购物车与结算页联动逻辑购物车页面的核心难点在于“批量计算总价”。用户勾选、取消勾选、修改数量、删除商品只要操作一个右下角的总金额就要立即重算。我采用的做法是前端维护一份购物车数据每次变动都调用一个本地方法重新遍历所有商品项只累加selected为 true 且checked为 true 的项然后setData更新总金额。结算页面更繁琐的地方在于优惠规则这个源码里我只做了简单逻辑满99元包邮。运费计算单独拆了一个方法calcShippingFee()以后想改成“全场免邮”或者“满299减40”都很方便直接调这个方法就行。提交订单前需要校验三件事商品库存是否充足、收货地址是否已填写、购物车勾选商品是否为空。这三个条件缺一个都要阻断提交流程并提示用户。有次测试的时候发现一个情况用户把最后一件秒杀商品加购后没下单过一会儿买了这时候购物车是勾选状态但库存已经不够了。所以提交订单时后端必须校验库存并且要从数据库实时取不能信前端传过来的参数。3.4 个人中心与订单列表个人中心的菜单项包括我的订单、收货地址、优惠券预留、联系客服、关于我们。数据展示上我用了热门词“小程序列表加载更多”提到的触底加载模式。订单列表的每条数据展示订单号、商品缩略图、订单状态、实付金额点击进去能看到订单详情。订单状态我用了数字字典0待付款、1待发货、2待收货、3已完成、4已取消。前端拿到状态码后统一通过statusText映射成中文这样后端不用返回冗余字段前端也方便做多语言适配虽然目前只有中文需求但代码习惯要保持。收货地址管理这边用一个开源地区选择组件来实现省市区三级联动数据源是china_area.json大概几千条数据打包进小程序后体积还能接受。选择完后把省市区名称和详细地址拼接存储提交到后端的是完整地址字符串这样后端不需要再做省市区表的联表查询逻辑简单而且不容易出错。4. 前后端联调与接口调试技巧4.1 本地开发环境搭建与联调配置很多人在本地跑小程序项目时会遇到一个很头疼的问题真机预览时请求不到本地后端接口。原因是真机上的localhost指向的是手机自己而不是你的电脑。解决方案有两个第一通过微信开发者工具的“不校验合法域名”选项关掉域名校验然后在工具右上角的详情设置里找到本地设置勾选“不校验合法域名、web-view业务域名、TLS 版本以及 HTTPS 证书”。开发模式下这样配置就可以用http://localhost:8000直接调试。第二如果手机和电脑在同一个局域网可以用电脑的局域网 IP Laravel 的开发服务器端口来请求接口比如http://192.168.1.100:8000。这里需要在 Laravel 的config/sanctum.php里把stateful数组加上你这台电脑的 IP否则跨域请求会被拦下来。CORS 跨域问题也是联调时绕不开的一环。Laravel 8 之后的版本自带了一个HandleCors中间件在app/Http/Kernel.php里已经默认注册了。你需要做的就是到config/cors.php里把allowed_origins改成[*]开发环境或者填上你的小程序域名。这里有个小细节小程序请求后端接口时Origin头是https://servicewechat.com/xxx如果你的allowed_origins没有这个域名请求就会失败。4.2 抓包调试的正确姿势榜单里热词“小程序抓包”、“charles使用教程”排得很靠前看得出大家在这块需求很强烈。说实话小程序抓包和网页抓包不太一样主要原因是微信开发者工具内置了网络调试功能在 Debug 模式下直接能看到每一个请求的 URL、请求头、响应体其实不需要额外抓包工具。但如果你想抓真机上的小程序请求就需要用到 Charles 了。步骤稍微有点多但跟着操作一遍就能记住电脑上打开 Charles菜单栏选择 Proxy - SSL Proxying Settings勾选 Enable SSL Proxying点击 Add 添加主机*.servicewechat.com和*.qq.com手机和电脑连同一个 Wi-Fi手机 Wi-Fi 设置里把代理改成手动服务器填电脑的局域网 IP端口填 Charles 默认的 8888手机浏览器访问chls.pro/ssl下载并安装 Charles 的根证书iOS 需要额外信任证书在 Charles 里右键想要看的接口选择 Save Response 就能把返回的 JSON 存下来分析。这里一定不要被热词中某些内容误导抓包本身是本地开发调试手段大家正常用于联调即可。我更推荐直接用微信开发者工具的 Network 面板既省事又安全数据一目了然。真机调试的必要性在于一些接口在工具预览正常但真机上可能因为代理问题、网速问题表现不一致这时候用真机调试加 Console 日志定位最靠谱。4.3 常见接口联调问题排查联调阶段最容易碰到的几类问题我统一整理成一张速查表现象原因解决方案请求 404路由未定义或参数绑定错误检查api.php里的路由定义确认参数名一致请求 500Laravel 代码报错打开storage/logs/laravel.log查看错误栈请求被 CORS 拦截跨域配置不完整检查config/cors.php放行对应 Origin返回数据为 null模型关联写错检查 model 里hasMany/belongsTo定义真机请求失败域名未校验开发者工具勾选不校验域名或配置合法域名接口响应慢导数据了没有加索引给外键字段加索引避免全表扫描有个坑必须提醒用 Laravel 自带的开发服务器php artisan serve在本地跑遇到并发请求时会出现假死现象这是因为 PHP 内置的服务器是单线程的。开发环境建议装个 Laragon 或者直接用 Docker 跑 Nginx PHP-FPM这样才会接近生产环境的表现。5. 部署上线与后端配置实践5.1 服务器环境要求与配置部署这套系统到生产环境推荐配置是 Nginx PHP 8.1 MySQL 5.7。PHP 版本千万别用太旧的Laravel 9 以上的版本要求 PHP 8.0 起步用 7.4 跑会直接报错。另一个坑是 PHP 的扩展php -m命令确认一下有没有fileinfo、openssl、pdo_mysql缺一个都起不来。Nginx 配置 Laravel 项目的核心是try_files指令官方配置长这样server { listen 80; server_name your-domain.com; root /var/www/your-project/public; add_header X-Frame-Options SAMEORIGIN; add_header X-Content-Type-Options nosniff; index index.php; charset utf-8; location / { try_files $uri $uri/ /index.php?$query_string; } location /favicon.ico { access_log off; log_not_found off; } location /robots.txt { access_log off; log_not_found off; } error_page 404 /index.php; location ~ \.php$ { fastcgi_pass unix:/var/run/php/php8.1-fpm.sock; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; include fastcgi_params; } location ~ /\.(?!well-known).* { deny all; } }域名配置好之后再到小程序后台把服务器域名加进去。这里要注意一个细节微信要求请求域名必须是 HTTPS而且证书必须有效在“开发管理 → 开发设置 → 服务器域名”里分别配置 request 合法域名、uploadFile 合法域名、downloadFile 合法域名。downloadFile 域名容易被忽略商品图片传到 CDN 后如果小程序里要用image标签展示那 CDN 域名必须加入 downloadFile 合法列表否则图片会显示不出来。5.2 .env 配置与安全注意事项Laravel 项目的关键配置都在.env文件里部署后第一时间要修改以下内容APP_ENVproduction把开发模式关掉避免错误信息直接暴露给用户APP_DEBUGfalse这个一定要改APP_DEBUGtrue的时候任何报错都会把文件路径和 SQL 语句直接打到页面上等于把一个完整的信息泄露接口暴露给攻击者DB_*数据库配置改成生产库数据库密码用强密码APP_KEY要重新生成命令是php artisan key:generate。另外强烈建议把.env文件加入.gitignore不然传到代码仓库里就老老实实把你的数据库密码、微信 AppSecret 这些敏感信息公之于众了。之前见过不少开源项目拉下来之后.env还躺在目录里这种操作属于安全事故级别的问题了。5.3 微信小程序上线审核要点小程序开发完提审之前有几件事必须确认否则白白浪费几天审核时间第一用户隐私协议必须完善。微信要求小程序必须说明收集了哪些用户信息以及用途。我这里的登录接口就收集了用户的 openid必须在小程序后台的“用户隐私保护指引”里声明确认。第二类目要选对。“玩转潮玩”这种手办商城类目应该选择“电商平台”或者“商家自营”如果没有对应资质需要补充。个人主体注册的账号做不了电商类目这是硬性限制。第三虚拟支付的问题要避雷。微信对虚拟商品的支付管控极严如果卖的是虚拟物品比如电子卡、积分微信支付额度会被冻结甚至封号。所以我这套源码默认走的是模拟支付就是为了规避这个问题。上线后真正接入微信支付销售的商品必须是实物手办。审核被拒最常见的理由有页面空白接口没通、类目不符合、没有客服入口、没有运营者联系方式。提交审核前自己最好走一遍核心流程从登录到商品浏览到下单确认每一步都顺畅能少走很多弯路。6. 源码获取与后续规划关于获取方式直接看个人主页简介或者文章评论区置顶代码我会打包成完整的工程文件包括数据库文件和部署文档。既然是开源分享我自己用的也是宽松的 MIT 协议也就是说你可以随意修改、商用甚至把它改成你的毕业设计或者接单项目注意接单前最好自己再改一遍代码逻辑以免撞衫。这套代码我后续还会继续更新目前已经在计划内的版本迭代方向包括优惠券模块后端做好优惠券发放、核销接口前端在结算页接入优惠券选择器双十一这种大促场景没有优惠券的商城根本没法玩。秒杀活动利用 Redis 做库存预扣解决高并发下的超卖问题。这个话题展开讲又是一篇长文等我测试稳定了再单独发一篇文章聊。后台管理界面目前后台只有 API我会再写一个简单易用的后台模板直接套一个开源 admin 框架让商品管理不用再敲命令行。多商户支持现在的手办圈子里很多人是二道贩子如果能做成平台模式让多个商家各自上架商品商业价值会大很多。我自己在实际操作中最大的体会是一套商城系统的难点根本不在“写代码”而在于把用户流程、库存、订单状态这些业务逻辑厘清楚。框架只是工具真正的活全在业务设计里。这套手办小程序源码我希望帮大家跳过“业务设计”这个坑直接拿到一套完整可用的方案在你自己的场景里去润色、去扩展。有问题欢迎在评论区交流我看到都会回。