我大学宿舍楼下那个小卖部,架子上的辣条和泡面永远是热的,尤其是晚上十点熄灯前,队伍能排到楼梯口。后来朋友拉我做一套“校园寝室小卖部校园零食网上商城配送系统”,我第一反应是:这不就是个普通商城吗?真把需求聊透之后才发现,校园配送比普通电商麻烦得多——楼栋怎么划分、配送窗口怎么安排、订单高峰期怎么不崩、库存怎么和线下柜台同步,每一件事都藏着细节。
项目最终选用 Node.js + PHP + Vue 这套组合落地:Vue 负责用户端和管理端的界面,PHP 扛商品、订单、库存这些业务接口,Node.js 负责 WebSocket 实时推送和配送状态流转。前后折腾了四个多月,从数据库设计到上线运营踩了不少坑,这篇就把完整思路和关键实操记录下来,给想在校内做类似项目,或者准备写课程设计、毕业设计的同学一个参考。
1. 项目整体设计与技术选型思路
1.1 寝室小卖部场景的业务痛点拆解
校园寝室场景和普通电商最大的区别,在于“物理边界”非常强。宿舍楼有门禁,外卖不能送上楼,配送只能送到楼下固定取货点;每栋楼之间的商品库存可能还不一样,一栋楼对应一个小卖部,也可能一个小卖部同时覆盖好几栋楼。这些约束直接决定了系统的业务模型,绝不是把商品列表、购物车、支付这三件套搬上去就行。
另一个痛点是订单高峰高度集中。课间十分钟、午饭前、晚上熄灯前,这三个时间段的订单量能占到全天的一半以上。线下排队会导致小卖部老板根本忙不过来,线上如果处理不好,同样会出现超卖、漏单、配送混乱。所以这套系统的核心解决的不是“能不能下单”,而是“高峰期能不能撑住”“配送能不能按楼栋聚合”“线上线下库存能不能实时同步”。
我还发现一个容易被忽略的点:学生用户并不需要多复杂的促销体系,他们最在意的是“晚上十点还能不能下单”“半小时内能不能送到楼下”。因此系统在功能优先级上,配送时间窗口和订单状态可视化的权重,反而比营销工具更高。这也是一个典型的场景驱动设计案例。
1.2 为什么是 Node.js + PHP + Vue 的混合架构
先说结论:这个组合不是为了炫技,而是让每种技术去干自己最擅长的事。
PHP 的强项在于 Web 业务接口的开发效率极高。商品增删改查、订单管理、用户管理这类 CRUD 操作,ThinkPHP 或 Laravel 框架下写起来非常顺手,而且部署成本极低,一台普通云服务器加个 Nginx 加 PHP-FPM 就能跑起来。做校园项目通常团队不大,运维能力有限,PHP 这套“上传即运行”的部署方式,能为后期维护省下大量精力。
Node.js 的强项则是实时通信和高并发连接。配送员接单、配送状态变更、用户在线查看订单进度,这些场景用 WebSocket 实现,体验远好于 PHP 轮询。Node 基于事件驱动的 IO 模型,在高峰期几百个配送员同时在线时,连接稳定性也有保障。我做了一个简单的拆分:PHP 负责所有常规 HTTP API,Node 负责 WebSocket 推送和一个轻量 BFF 聚合层,两边通过内网 HTTP 互通,职责清晰。
Vue 作为前端框架,主要是看中它的组件化开发效率和移动端适配能力。学生用手机浏览器访问居多,Vue 搭配 Vant 组件库,可以快速搭建出一套接近原生 App 体验的移动端商城页面;商家端和管理后台则用 Element Plus,桌面端布局更顺手。组件复用能减少大量重复开发,一个表单组件、一个订单卡片组件可以在多个页面复用。
有人会问,为什么不干脆用纯 Java Spring Boot + Vue?不是不行,而是对校园项目来说,Spring Boot 的项目体积、启动内存、部署复杂度都偏重。小团队维护一套 Spring Boot 加上打包部署环境,成本明显高于 PHP + Node 的组合。如果团队本身就熟悉 PHP 和 JavaScript,用这套混合架构,开发节奏会快得多,后期接手的人也好找。
1.3 三端职责边界与分工表
系统的使用角色可以分成四处:学生(用户端)、小卖部老板(商家端)、配送员(配送端)、系统管理员(管理后台)。我按端把职责边界整理清楚,前端和后端开发都能对齐目标。
| 端 | 技术方案 | 核心功能 |
|---|---|---|
| 用户端(学生) | Vue + Vant 移动端 | 浏览商品、按楼栋筛选、购物车、下单支付、配送状态查看 |
| 商家端(老板) | Vue + Element Plus | 商品上下架、库存管理、接单/拒单、订单备注 |
| 配送端(配送员) | Vue 移动端 | 待接单列表、配送单分配、状态流转、送达确认 |
| 管理后台 | Vue + Element Plus | 用户管理、楼栋管理、商品分类、数据看板 |
| 服务端 | PHP + Node.js | PHP 处理业务 API,Node 处理 WebSocket 推送与 BFF 聚合 |
这个分工的好处是前后端可以完全并行开发。后端按接口文档提供 API,前端用 Mock 数据先把页面做出来,等接口就绪后联调。Node 的 BFF 层承担了一部分接口聚合适配的工作,比如把 PHP 返回的商品信息与配送实时状态拼装成前端需要的结构,前端页面逻辑可以保持干净。
2. 核心功能模块拆分与数据库设计
2.1 用户端商城模块:从逛商品到下单支付
用户端是学生直接接触的界面,核心流程是“选商品—加购物车—下单—支付—等配送”。商品列表按照零食、饮料、泡面、日用品几个大类划分,首屏根据用户所在楼栋直接过滤出能配送的商品,避免出现“能看不能买”的情况。这一步在普通电商里很常见,但在校园场景里是刚需,因为每个楼栋对应的可售商品和库存是独立的。
商品详情页除了图文介绍,我还接入了视频展示。一些零食的开箱视频、泡面的测评短视频,用 .m3u8 格式存到对象存储,前端用 hls.js 播放。这里有一点要注意:hls.js 对低版本浏览器的兼容性一般,校园里学生手机型号很杂,所以播放前要判断原生支持情况,不支持的原生 HLS 时再降级到 hls.js 方案。
下单环节有一个关键设计:用户必须选择配送时间段。系统只开放三个窗口:午餐(10:30-12:30)、晚餐(16:30-18:30)、夜宵(21:00-23:00)。选择窗口之后,页面会显示该窗口剩余可接单量,避免用户下单后没人配送。支付方面除了微信/支付宝,我还接了卡密兑换功能,老板可以批量生成兑换卡密,学生用卡密抵扣订单金额,校园里做活动特别实用。
2.2 商家后台与配送端模块
商家后台是老板每天用的工具,界面不能复杂,操作要越快越好。商品管理支持一键上下架、批量改价、批量导入导出。这里我用 PHP 配合 PhpSpreadsheet 处理 Excel 批量导入,老板从供货商拿到商品表格,整理好格式之后直接传上去,几百个商品几秒钟就入库。
订单管理是商家端的重心。订单按“待接单—备货中—已交给配送员—已完成”四个状态排列,老板只需要点“接单”,系统会自动推送通知到配送端。库存同步也很关键:线下卖出一瓶可乐,老板在柜台系统里减一个库存,线上立刻体现;线上订单支付后,系统预扣库存,避免同一件商品线上线下重复卖出。
配送端是给配送员用的移动端页面,核心功能就是“抢单”和“配送”。系统按楼栋和时间窗口把订单聚合成配送单,配送员在待接单列表里抢单,抢到后按楼栋批量配送。配送单列表只显示楼栋、取货点编号和订单数量,配送员不需要看复杂的商品明细,效率反而更高。
2.3 数据库表结构设计与库存防超卖方案
数据库是整个系统的地基,表设计直接决定后期开发的顺畅程度。我按业务边界把表拆成几个模块:用户与权限、楼栋与店铺、商品与库存、订单与支付、配送与优惠。
| 表名 | 关键字段 | 说明 |
|---|---|---|
| users | id, openid, name, phone, building_id, role | 角色区分学生/老板/配送员/管理员 |
| buildings | id, name, address, shop_id | 楼栋与店铺的映射关系 |
| shops | id, name, owner_id, status | 小卖部店铺信息 |
| products | id, shop_id, category_id, name, price, stock, status | 商品库存和上下架状态 |
| orders | id, order_no, user_id, shop_id, status, total_amount, delivery_window, building_id | 订单主表,状态机流转 |
| order_items | id, order_id, product_id, quantity, price | 订单明细,快照商品信息 |
| deliveries | id, order_group_no, delivery_user_id, building_id, window, status | 配送单,按楼栋聚合 |
| coupons | id, code, status, user_id, expire_at | 卡密/优惠券 |
订单表的状态机是系统里最重要的逻辑。我定义了五个状态:pending(待付款)、paid(已付款待接单)、accepted(已接单备货中)、delivering(配送中)、completed(已完成),另外加两个异常状态:cancelled(已取消)、refunding(退款中)。前端页面上的状态展示、按钮可用性都由这个状态机驱动,避免用户操作到不该点的按钮。
防超卖是校园商城最容易踩的坑。学生下单高峰期,同一袋辣条可能几十个人同时下单。我用的是“预扣库存 + 支付确认”方案:用户下单时执行 UPDATE products SET stock = stock - 1 WHERE id = ? AND stock > 0,通过影响行数判断是否扣减成功。如果扣减成功,订单进入待支付,15 分钟内未支付自动释放库存;支付成功后库存正式锁定,配货时不会再校验。
订单聚合配送也是表设计时要提前想好的。我单独建了一张 deliveries 表,把同一配送窗口、同一楼栋的多个订单聚合到一个配送单里。配送单生成后,配送员只需要认领这一个配送单,按楼栋打包配送,大幅减少了配送员的跑腿次数。
2.4 配送时间窗口与订单聚合策略
配送时间窗口要结合学校作息来定。我们学校午休一小时半、晚自习后到熄灯前是流量高峰,所以窗口就定为午餐、晚餐、夜宵三个。每窗口设定接单上限,达到上限后前端直接显示“该时段已约满”,用户只能选下一个窗口,这个限制要同时在 PHP 接口里做校验,前端隐藏按钮只是体验层的做法。
订单聚合策略也要提前规划。系统每天在窗口开始前 30 分钟,把已支付订单按楼栋分组,生成配送单。比如 3 号楼在夜宵窗口有 15 个订单,就自动生成一个“3 号楼夜宵配送单”,打印出一张商品汇总小票,配送员凭小票去柜台取货。这样既减轻柜台拣货压力,也让配送员每趟只跑一栋楼。
3. 开发环境搭建与核心步骤实操
3.1 Node.js 安装与 npm 权限问题一次解决
开发环境的第一步就是装 Node.js。很多同学卡在这一步很久,尤其是 Windows 系统。我建议从 Node.js 官网下载 LTS 版本安装包,不要追求最新版,LTS 版本的稳定性和生态兼容性最好。安装时一直点下一步就行,默认会配置好环境变量,安装完成后打开命令行,输入 node -v 和 npm -v,能输出版本号就说明装好了。
如果你日常用的终端是 Windows PowerShell,大概率会遇到一个经典报错:
npm : 无法加载文件 D:\Program Files\nodejs\npm.ps1,因为在此系统上禁止运行脚本
这个问题的原因是 PowerShell 默认执行策略是 Restricted,不允许执行任何 .ps1 脚本文件。解决办法是:以管理员身份打开 PowerShell,执行下面的命令:
Set-ExecutionPolicy RemoteSigned
执行后按 Y 确认,关掉终端重新打开,npm 命令就能正常使用了。如果你不想改动系统策略,还有一个临时方案:在 PowerShell 里输入 cmd 切到命令提示符环境,再执行 npm 命令,绕开 PowerShell 的脚本策略限制。
这里再说一个经验:建议装一个 nvm-windows 来管理 Node 版本。校园项目的依赖可能是不同时期装的,有的要求 Node 14,有的要求 Node 18,用 nvm 可以随时切换版本,省去反复卸载重装的麻烦。平时开发用 VS Code 写前端,如果习惯把 PyCharm 当主力 IDE,也可以安装 NodeJS 插件,直接在 IDE 终端里运行 npm 命令,原理一样,看个人习惯。
3.2 Vue 项目初始化与依赖安装
Vue 项目我推荐用 Vite 作为构建工具,启动速度比旧版 Vue CLI 快一个量级。创建项目可以直接执行:
npm create vue@latest
这个命令会交互式询问是否安装 Vue Router、Pinia、ESLint 等,根据自己的需求勾选。校园商城项目建议勾选 Vue Router 和 Pinia,ESLint 可选,项目初期保持轻量,后面代码多了再补规范化也不迟。
项目创建完成后,进到目录执行 npm install 安装基础依赖,然后再装其他必要库。前端移动端页面我用的 Vant,管理后台用的 Element Plus,HTTP 请求统一用 axios。商城商品详情需要播放 .m3u8 视频,还要安装 hls.js。这些命令可以一次装完:
npm install vant element-plus axios hls.js pinia vue-router@4
依赖装完之后,在 main.js 里注册路由、Pinia、UI 组件库。这里要提醒一下:Vant 和 Element Plus 都是按需引入更优,如果图省事全部引入,项目包体积会很大,首次加载会明显变慢。我实际项目里用了 unplugin-vue-components 插件做组件自动按需引入,效果很好,强烈推荐。
项目的目录结构也值得一开始就规划好。我的习惯是 src 下分 views、components、router、stores、api、utils 六个目录:views 放页面组件,components 放可复用组件,router 放路由配置,stores 放 Pinia 状态,api 统一管理接口请求,utils 放工具函数。这种结构到项目后期会非常舒服,新页面进来直接往 views 里加文件,不需要纠结放哪里。
3.3 PHP 接口开发、跨域处理与联调
PHP 后端我选了 ThinkPHP 6 框架,原因很实际:中文文档完善,命令行工具方便,部署要求低。创建控制器、模型、数据库迁移都很顺手,校园项目团队上手快。项目按模块划分:user、shop、product、order、delivery、coupon,每个模块一个目录,避免把所有逻辑堆在一个文件里。
接口规范统一是前后端联调的前提。我们约定所有接口返回格式为:
{ "code": 0, "msg": "ok", "data": {} }
code 为 0 表示成功,非 0 表示业务异常,msg 是给前端的提示信息。前端在 axios 拦截器里统一判断 code,非 0 时弹出对应的 msg,这样前端业务代码不用每处都写错误处理。
前后端联调时最常见的坑是跨域。Vue 开发服务器默认跑在 5173 端口,PHP 接口跑在 8000 端口,不同端口下浏览器会拦截跨域请求。开发阶段的解决办法是在 PHP 入口文件或中间件里设置响应头:
header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS'); header('Access-Control-Allow-Headers: Content-Type, Authorization');
如果 PHP 接口同时要兼容 JSONP 调用,可以判断请求参数里有没有 callback 字段,有的话返回 JSONP 格式的 JS。但实际项目中我建议统一走 CORS,JSONP 只用于个别跨域场景的兜底,毕竟 GET 请求 JSONP 还限制较多,POST 支付场景根本没法用。
PHP 处理 JSON 时还有一个高频坑:中文被转成 Unicode 编码。用 json_encode 时一定要加 JSON_UNESCAPED_UNICODE 参数,否则前端拿到的是 \uXXXX 形式的字符串,虽然能正常显示,但在一些日志排查、签名计算场景会踩坑。另外别忘了设置时区,PHP 默认时区是 UTC,和北京时间差 8 小时,订单时间如果显示错乱,基本就是这个问题。
4. 开发过程中常见问题与排查技巧
4.1 npm 脚本执行报错与镜像源问题
我在整个开发过程中,npm 相关的报错遇到最多,基本都是环境和源的问题。第一个就是前面提到的 npm.ps1 权限报错,注意它的路径可能会出现两种变体:装在 Program Files 目录下的会报 D:\Program Files\nodejs\npm.ps1 或 C:\Program Files\nodejs\npm.ps1,装在 Program Files (x86) 目录下的会报 D:\Program Files (x86)\nodejs\npm.ps1。无论哪种,解决办法都一样,改执行策略或者切 CMD。
第二个常见报错是 npm ERR! EACCES permission denied。这个问题在 macOS 和 Linux 上最常见,本质是全局安装目录没有写权限。解决办法有两个:一是用 sudo 临时提权,但不推荐;二是把 npm 全局目录改到当前用户目录下,如下所示:
npm config set prefix ~/.npm-global
改完之后把 ~/.npm-global/bin 加进 PATH 环境变量,再重新 npm install -g 一下,问题就彻底解决了。
第三个问题是安装依赖超时或者 404。npm 默认源是国外的,校园网络环境时常不稳定。我直接将 registry 切换到国内镜像,提升明显:
npm config set registry https://registry.npmmirror.com
切换后 npm install 的速度能快好几倍。但有一点要注意:发布或调试私有包时,镜像同步可能有延迟,遇到“找不到某版本”的情况可以临时切回默认源验证。
第四个问题不在报错,但在团队协作中很容易出现:npm install 之后命令找不到。原因多半是全局安装路径不在 PATH 环境变量里。Windows 下安装 Node 后会自动配置,但如果你手动改过 Node 安装目录,记得把 node.exe 所在路径和全局 node_modules 的 bin 路径都检查一遍。
4.2 Vue 路由参数、状态管理与其他常见坑
Vue Router 传参是新手最容易搞混的点。query 方式传参会把参数拼在 URL 上,刷新后保留;params 方式刷新后会丢失,除非在路由配置里显式声明参数名并配合 history 模式处理。商城项目里的商品 ID 我用 query 传递,因为商品链接经常要分享给别人,URL 里带着 ID 更可靠;但订单详情这类业务,我用 Pinia 的 store 保存,避免 URL 太长和敏感信息暴露。
状态管理用 Pinia 之后,我要强调一个习惯:所有登录状态、购物车数量、订单实时状态都要从 store 读取,页面组件里不要自己定义一份副本。我踩过这样的坑:购物车组件里自己维护了一个数量变量,接口返回新数据后,组件里的旧副本没有更新,导致用户看到数量和实际不一致。后来统一从 store 拿数据,只在组件里维护纯 UI 状态,问题彻底解决。
Vue DevTools 也是必备工具。有些同学安装插件后发现页面没有调试面板,多半是浏览器扩展权限没有打开,或者项目开发服务器没有运行。安装后记得在站点权限里勾选“允许访问文件网址”,同时要保证当前项目处于 development 模式。生产环境构建的代码会被压缩混淆,DevTools 里看到的组件树和 store 状态基本不可读。
地图相关的功能,我用了腾讯地图的 JavaScript API。校园配送不需要精确到街道,主要是在配送单详情里显示楼栋位置标记。Vue 里使用地图 API 时,初始化脚本在 onMounted 生命周期里执行,最好用 jsapi-loader 动态加载,避免把整个地图脚本打包进主包,影响首屏速度。如果只是展示静态位置,也可以直接用静态地图图片,连 SDK 都不用引。
4.3 PHP 接口联调中的跨域与编码问题
接口联调阶段踩的坑,九成都在跨域、编码、参数格式这三类。跨域问题除了设置响应头,还要注意一个细节:浏览器会先发送 OPTIONS 预检请求,如果 PHP 接口没处理这个请求,就会导致浏览器判定跨域失败。我习惯在框架的公共中间件里判断请求方法为 OPTIONS 时,直接返回空响应并带好 CORS 头,状态码 204,就能顺利通过预检。
编码问题除了 JSON_UNESCAPED_UNICODE,还有数据库连接时的字符集设置。PHP 连接 MySQL 时,如果连接字符集不是 utf8mb4,中文和 emoji 表情都可能变成问号。我一般会在数据库配置里强制设置 charset 为 utf8mb4,同时在订单备注字段也允许用户输入 emoji,实测显示正常。商品名称和图片链接的编码也要统一,前后端都约定用 UTF-8,基本不会再遇到乱码。
接口参数格式问题主要出现在时间格式和数字类型上。我建议后端接口统一返回时间戳,前端自己转成需要的展示格式;金额用“分”作为单位,前端展示时再除以 100,避免浮点数精度误差。PHP 原生的浮点数运算在金额计算上有坑,涉及价格计算统一用 intval 转成整数后再算,订单金额、优惠券抵扣都不会出现 0.1 + 0.2 不等于 0.3 的尴尬。
文件上传也是 PHP 开发经常踩坑的地方。php.ini 默认 upload_max_filesize 是 2M,商品图片稍微大一点就会被拒绝。我会把 upload_max_filesize 和 post_max_size 同时调大到 20M,并且在上传接口里做文件类型和尺寸校验,只允许 jpg、png、webp 图片,防止有人往服务器传木马文件。安全层面还要注意验证文件内容头,不能只看扩展名,这类问题基本都在上线前的安全测试中被发现。
4.4 前后端接口约定与联调习惯
前后端联调效率低,根本原因是接口约定不清晰。我建议项目一开始就统一使用 Apifox 或 Postman 管理接口文档,字段名、返回结构、错误码都在文档里写清楚。后端写完一个接口标注“已就绪”,前端就针对这个接口开发页面,如果字段变更,在文档里同步更新,并有变更记录,避免群里沟通碎片化。
字段命名规范建议全局用 snake_case(下划线命名)。PHP 后端天然习惯下划线命名,前端 JS 虽然多用 camelCase(驼峰命名),但通过 axios 拦截器做一次字段转换并不困难。关键是全项目统一,别一会儿 user_id 一会儿 userId,前端处理起来很容易精神分裂。我项目里还用了 TypeScript 定义接口返回类型,能在编译阶段就发现字段类型不匹配的问题。
接口异常处理也要形成规范。前端 axios 拦截器统一处理 HTTP 状态码 401(未登录)、403(无权限)、500(服务器异常),业务抛错信息统一用后端返回的 msg。后端接口的异常不要直接抛堆栈给前端,一定要包一层 try-catch,记录日志后返回友好的错误信息。这样排查问题时,通过日志能快速定位是哪一层出的问题,而不是拿着浏览器控制台到处猜。
5. 部署上线与寝室场景运营经验
5.1 Nginx 反向代理与 PM2 进程管理
上线部署时,我选了一台 2 核 4G 的云服务器,Installed CentOS 系统。架构很简单:Nginx 监听 80 和 443 端口,两种请求分别处理——常规 HTTP API 转发给 PHP-FPM,WebSocket 长连接转发给 Node 服务。Nginx 关键配置如下:
# PHP 接口 location /api/ { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } # Node WebSocket 推送 location /socket/ { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; }Node 服务的进程管理我用 PM2,好处是进程崩溃后自动重启,还能查看日志。部署后执行 pm2 start app.js --name school-mall 启动,pm2 logs 实时查看日志,pm2 save 保存当前进程列表,最后 pm2 startup 配置开机自启。这样服务器重启后 Node 服务会自动拉起,不需要手动登录维护。
数据库备份也是上线前必须要做的工作。我每天凌晨 2 点用 crontab 执行 mysqldump 备份,备份文件保留最近 7 天。另外上线前务必关掉 PHP 错误显示,php.ini 的 display_errors 改为 Off,error_reporting 设置记录到日志文件,避免暴露路径和 SQL 信息给用户。
5.2 校园场景运营中的数据与物流优化
系统上线后,最大的问题不是技术,而是运营节奏的调整。第一个星期,老板反馈夜宵窗口经常爆单,但配送员不够。我在后台统计了各个窗口的平均订单量之后,把夜宵窗口的接单上限调低,同时提前在群里招募了几个兼职配送员,只负责 21:00-23:00 这个时段,一下子缓解了压力。
数据看板还发现了一个有趣的现象:泡面和辣条是复购率最高的商品,但库存周转最快;饮料类目的毛利率低,可用户基本都是顺手带一瓶。根据热销排行,我帮老板规划了“每周特惠”活动,把高毛利零食做组合套装,用 PHP 批量生成了一批兑换卡密,通过学生群发放。卡密要设置有效期和单次使用限制,防止被批量兑换。
配送体验优化的关键是“最后一公里的确定性”。用户最焦虑的不是配送慢,而是不知道什么时候到。我在用户端订单详情页加了配送状态时间线:已接单、已出店、配送中(显示当前配送单序号)、已送达。四十分钟的配送流程,每一步都有时间戳,学生等单焦虑感大幅降低。实测退款投诉率下降了一半,这比任何宣传都管用。
轮询和推送的取舍上,我一开始想全部用 WebSocket,后来发现订单状态通知用 WebSocket 推送,商品列表、库存这些用普通 HTTP 接口就够了。WebSocket 只维护和用户端的实时连接,把消息队列里的事件推送到前端。这样 Node 服务的负担可控,高峰期每台机器撑几千个连接没有问题。
项目上线跑了将近一个学期,最深的感受是,技术选型永远要跟着业务场景走。Node.js 和 PHP 的混搭,在外人看来可能有点“野路子”,但在校园寝室这类小体量、强实时诉求的场景里,这套方案用最少的成本解决了最难的问题。如果你也要做类似的项目,我建议先把楼栋映射、配送窗口、库存同步这三件事想清楚,再动页面。最后分享一个小技巧:凡是涉及状态流转的订单操作,前端不要自己维护状态,一切以服务端返回为准,能少踩一半的坑。