ARTICLE DETAIL

资讯详情

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

Node.js+Vue前后端分离零食商城系统设计与部署全攻略

Node.js+Vue前后端分离零食商城系统设计与部署全攻略 说个真实的场景我前段时间帮一个开了几年实体零食店的朋友搭线上商城预算不高、要跑得快、后面还得持续加功能最后定的方案就是“Node.js Vue”这套前后端分离组合。项目标题里写的“nodejs基于Vue的小零食超市购物商城销售系统”听起来挺长拆开看其实就是三件事后端用 Node.js 做接口服务前端用 Vue 写商城页面中间跑通一套完整的电商购物流程——商品浏览、购物车、下单结算、支付回调、订单管理这些核心环节。这篇文章我打算完整梳理一遍这套系统的设计与落地过程包括技术选型为什么这么定、数据库表怎么设计、前后端联调的那些坑、以及部署上线时最容易翻车的几个地方。无论你是在校学生做毕业设计还是刚转行想拿个全栈项目练手或者真有小店要上线销售渠道照着这个思路走能少走很多弯路。1. 项目整体设计与技术选型解析1.1 为什么零食商城选了 Node.js 而不是 Java 或 PHP先说后端。很多人一听到“电商系统”就觉得必须上 Spring Boot、MySQL、Redis 那套重型组合但小零食超市这种场景真的没必要。核心原因有三个。第一业务体量决定技术复杂度。零食超市的商品种类再多也就是几百上千个 SKU日均订单量在初期可能就几十单这种量级用 Node.js 的 Express 或 Koa 跑接口完全没有压力反而是 Java 那套一堆注解、依赖注入、Mapper XML 写起来特别沉本来一周能搞完的活儿被框架本身的学习成本拖到一个月。第二开发效率高。JavaScript 一门语言通吃前后端意味着你不需要维护两套语言心智。我在实际开发中比如商品列表接口返回的数据结构前端要什么形状我直接在后端组装好返回联调的时候几乎不用来回扯皮因为没有类型转换的摩擦。第三生态成熟。Node.js 在处理 I/O 密集场景表现很好电商系统的大部分操作都是增删改查真正耗 CPU 的复杂计算并不多。而且 npm 上有大量现成方案鉴权用 jsonwebtoken、文件上传用 multer、参数校验用 joi每个都是开箱即用的稳定库踩坑率远低于自己去造轮子。当然 Node.js 也有它不适合的场景比如强事务、复杂报表分析但零食商城这种偏零售展示、下单流转的系统Node.js 完全是“杀鸡用了把刚好趁手的刀”。1.2 前端锁定 Vue 的三个直接原因前端选 Vue 也很明确不是因为它比 React 好而是因为它对这个场景最合适。一是上手曲线平缓。如果你之前只写过 HTML、CSS、原生 JavaScriptVue 的模板语法会让你感觉非常自然——{{ }}插值、v-for循环、v-if判断这些指令像是对 HTML 的增强而不是像 JSX 那样要重新建立组件思维。我接触过不少想快速做出成品的新手用 Vue 两周就能写出像模像样的页面用 React 光 hooks 的依赖数组就能卡住好几天。二是配套工具链省心。Vue Router 管页面跳转、Pinia 管全局状态购物车这种跨页面共享的数据特别需要、Element Plus 管后台界面组件这些都是 Vue 官方或生态内公认度最高的方案组合起来一致性很好。React 那边路由用 react-router-dom、状态用 redux 还是 zustand团队内部都得吵半天。三是社区中文资料丰富。这点对中文开发者来说太重要了。你在开发中遇到任何问题比如动态路由怎么传参、组件缓存怎么配置搜索出来的高质量博客和问答基本都是 Vue 的。对于这个项目的目标人群——学生、转行者、小店主——学习资源可获取性是选型时必须要考虑的隐性成本。前后端分离还有一个额外的好处以后想给商城加个移动端 H5或者接个小程序后端接口不用大改前端重新做一层就行。1.3 系统角色与整体架构划分这套系统我分了三个角色普通用户、管理员和系统本身的后台服务。普通用户看到的是商城前台——商品分类浏览、关键词搜索、商品详情、加入购物车、结算下单、查看订单状态。管理员进入的是后台管理界面——商品上下架、库存调整、价格修改、处理订单发货、查看销售概况。整个系统拆成两个前端应用加一个后端服务各自独立部署但共享同一套数据库和接口。架构层面具体是这样的前台商城Vue 3 Vite Vue Router Pinia Element Plus后台管理同一套技术栈但独立路由和布局后端服务Node.js Express提供 RESTful API数据存储MySQL 存储业务数据Redis 存验证码和热数据处理初期量小可以只用 MySQL文件存储本地静态目录后续量大了再迁 OSS这里有个经验之谈不要一上来就追求微服务、读写分离、消息队列。小项目最怕过度设计你以为是预留扩展空间实际上是在给自己挖维护的坑。我见过太多毕业设计上了 RabbitMQ 结果消息丢失了一整天查不出原因的真没必要。2. 核心功能模块拆解与数据库设计2.1 电商系统的五个关键模块零食购物商城从用户视角看核心链路就是“逛 → 加 → 结算 → 付 → 查”对应到系统里是五个模块。商品模块分类、品牌、规格比如一包薯片有原味和番茄味、价格、库存、上下架状态、主图和详情图。零食更新换代很快所以必须支持商品批量上下架和快速编辑。购物车模块这个模块有两个实现维度。未登录状态下用本地存储localStorage存购物车数据用户关掉浏览器再打开还在登录后切换到后端存储这样换设备也不会丢。我在实际开发中是先做本地版本因为上线初期很多用户懒得注册下单链路一样能走通。订单模块订单是整个系统的核心载体它把用户、商品、金额、收货地址、支付状态全部关联起来。从下单那一刻起订单要经历待付款、已付款待发货、已发货待收货、已完成、已取消这么几个状态每一步都需要可追溯。用户模块注册登录、个人信息、收货地址管理。密码加密我用的是 bcryptjsToken 鉴权用 JWT后端在请求拦截器里校验 Authorization 头。后台管理模块商品管理、分类管理、订单处理、用户列表。这里有一个容易被忽略但很关键的点——后台操作必须做权限校验不能让普通用户直接请求管理接口改数据。2.2 数据库表结构设计要点数据库我按“用户、商品、订单、购物车”四条线拆了九张核心表这里挑几张讲设计思路。用户表userid、username、passwordbcrypt 后的密文、nickname、avatar、phone、create_time。商品表productid、category_id、name、subtitle副标题、main_image、detail、price实际售价、original_price划线价、stock、sales销量、status是否上架。price 字段我用的是 DECIMAL(10,2) 而不是 FLOAT这是必须强调的——浮点数在电商金额计算中会产生精度误差1.1 2.2 这类问题在结算时会造成实际金额差错必须用定点数。订单表orderid、order_no业务订单号、user_id、total_amount、pay_amount、pay_type、status0待付款 1已付款 2已发货 3已完成 4已取消 5退款、receiver_name、receiver_phone、receiver_address、remark、create_time、pay_time、ship_time。订单明细表order_itemid、order_id、product_id、product_name下单时的商品名快照、product_image、current_unit_price下单时单价快照、quantity、total_price。为什么要做快照这是很多新手容易忽略的地方。用户下单之后如果商家改了商品价格或者删除了商品用户的订单记录不能跟着变——用户需要看到的是“我下单时买的是什么价”。所以订单明细里必须冗余一份商品名称、图片、价格信息不能只存 product_id 再去关联查询。购物车表cartid、user_id、product_id、quantity、checked。checked 字段表示这个条目是否被勾选参与结算这是购物车“部分结算”功能的基础。表之间用外键逻辑关联但物理层面我一般不建外键约束而是在服务层保证数据一致性。原因是高并发写入时外键校验会造成性能损耗而且一旦数据有问题删改操作会被约束卡得很死。实际开发中用代码控制关联关系配合索引已经足够。2.3 订单号生成与库存扣减方案业务订单号的设计看着不起眼但做不好就出乱子。订单号必须全局唯一数字且只能单调递增方便后续退款对账和客服排查。我用的规则是时间戳精确到秒 用户ID后四位 四位随机数例如20250610143512_1023_8934。如果同一个用户同一秒内下了两单随机数能确保不冲突后续接支付平台订单号可以直接作为商户订单号传过去方便回调匹配。库存扣减的方案我对比过三种。第一种是先查库存再判断是否够用够用就更新——这是最简单的“先检查后操作”模式但在并发场景下会出现超卖两个请求同时查到库存还剩1件都执行了扣减最后库存变成-1。第二种是乐观锁方案更新时带上库存条件可以写成UPDATE product SET stock stock - 1 WHERE id ? AND stock 0通过受影响行数判断是否扣减成功。这比第一种好得多但如果是同一个用户买多件需要扣减循环里逐次判断。第三种是 Redis 预扣减加异步同步适合大型系统。这个项目我用的是第二种再配合 MySQL 的SELECT ... FOR UPDATE锁行事务内先锁行再扣库存成功率高且不会超卖。推荐方案下单接口放在事务里先查商品信息并锁定行记录把库存扣减和订单创建放在同一个数据库事务中提交任何一个环节失败就整体回滚这样能保证一致性。3. 实操过程从零搭建到核心功能实现3.1 Node.js 安装与环境配置避坑指南开始写代码之前环境这关就卡住了不少人。Node.js 的安装有几个关键点。Node.js 建议直接去官网下载 LTS 版本安装包不要下载 Current 版LTS 是长期维护版稳定性优先。以我常用的 18.x LTS 为例安装时注意一个选项——安装向导里会问你“是否需要自动安装必要的原生模块编译工具”这个可以勾上省得后面装 bcrypt 这种需要编译的包时到处找 Python 和 C 工具链。安装完第一件事是验证环境变量。打开终端Windows 用 PowerShellmacOS/Linux 用自带终端输入node -v npm -v如果提示找不到命令大概率是环境变量没配上。Windows 下安装程序一般会自动把 Node.js 加进系统 PATH但偶尔会漏掉。手动检查方法右键“此电脑” → 属性 → 高级系统设置 → 环境变量确认 PATH 里有 Node.js 的安装路径。macOS 下如果用的是安装包一般不用手动配如果是用 brew 安装的路径通常是/usr/local/bin/nodeecho $PATH看一下有没有/usr/local/bin。还有一个高频问题相信很多人搜过“npm : 无法加载文件 npm.ps1因为在此系统上禁止运行脚本”。这个报错的根源是 Windows 的 PowerShell 执行策略默认是 Restricted禁止执行脚本。解决方案很简单以管理员身份打开 PowerShell执行以下命令然后重启终端Set-ExecutionPolicy RemoteSigned -Scope CurrentUser选Y确认即可。这个策略的意思是本地编写的脚本可以运行从互联网下载的脚本必须有可信签名。它对日常开发没有任何副作用也不会带来安全风险。如果重启后还报错检查一下是不是多个版本的 Node.js 环境变量互相冲突卸载干净后重装一次一般就解决了。国内用户还建议把 npm 源切到国内镜像不然下载 Electron 这种几百 MB 的包时速度会让人怀疑人生。常规操作分两种用官方命令npm config set registry https://registry.npmmirror.com或者用 nrm 这个工具来切换源。我个人推荐前者简单直接全局生效。顺便提一句npm 偶尔因为各种原因装不上包时建议先npm cache clean --force清一下缓存再删除node_modules和package-lock.json重新执行npm install。这个“三板斧”解决了我开发中七八成的依赖安装问题。3.2 前端项目创建与工程结构组织前端我用 Vite 而不是 Vue CLIVite 在大文件项目上冷启动和热更新的速度优势明显新项目官方也默认推荐 Vite。创建项目的命令npm create vitelatest shop-mall -- --template vue执行完进入目录、安装依赖、启动开发服务器cd shop-mall npm install npm run dev打开浏览器访问终端里输出的本地地址看到 Vite 的默认欢迎页就说明环境没问题。工程目录组织上我推荐清晰的分层结构用左下角的树形来直观展示src/ |-- api/ // 所有接口请求封装按模块拆分product.js, cart.js, order.js, user.js |-- assets/ // 静态资源 |-- components/ // 公共组件ProductCard, CartItem, OrderCard |-- router/ // 路由配置文件 |-- stores/ // Pinia 状态管理cartStore, userStore |-- views/ // 页面组件Home, ProductList, ProductDetail, Cart, Checkout, OrderList, Admin |-- utils/ // 工具函数request.jsaxios 实例封装, format.js |-- App.vue // 根组件 |-- main.js // 入口文件一个关键配置在vite.config.js——跨域代理。开发环境下前端跑在 5173 端口后端跑在 3000 端口直接发请求必然跨域。用 Vite 的 proxy 配置把/api前缀的请求转发到后端// vite.config.js export default defineConfig({ server: { proxy: { /api: { target: http://localhost:3000, changeOrigin: true } } } })配置之后前端代码里请求/api/products就等价于请求http://localhost:3000/api/products开发阶段不用后端配 CORS省掉一大半联调烦恼。注意生产环境部署时这个代理不起作用需要靠 Nginx 转发这个在后文部署章节再展开。3.3 后端项目搭建与 RESTful API 设计后端我用 Express 框架创建方式直接手工搭建目录不依赖脚手架这样更清楚每个文件的作用。mkdir server cd server npm init -y npm install express mysql2 cors jsonwebtoken bcryptjs multer joi dotenv核心依赖逐个说明都是实际开发中跑过、验证过的。expressHTTP 框架路由和中间件机制mysql2数据库驱动支持 Promise 写法相比 mysql 包更现代cors跨域中间件jsonwebtoken签发和校验 JWTbcryptjs密码加密纯 JavaScript 实现不用编译原生模块multer文件上传中间件处理商品图片joi参数校验避免接口被脏数据打崩dotenv加载 .env 环境变量文件后端的目录结构server/ |-- app.js // 应用入口挂载中间件和路由 |-- config/ | |-- index.js // 配置读取端口、数据库连接信息、JWT密钥 |-- routes/ // 路由定义productRoutes.js, cartRoutes.js, orderRoutes.js, userRoutes.js |-- controllers/ // 控制器业务逻辑处理 |-- middleware/ // 中间件authMiddleware.js, uploadMiddleware.js |-- models/ // 数据模型层封装 SQL 查询 |-- utils/ // 工具JWT 签发、响应格式化 |-- uploads/ // 商品图片静态目录接口设计遵循 RESTful 风格列举核心接口方法路径功能鉴权GET/api/products商品列表分页搜索分类筛选否GET/api/products/:id商品详情否POST/api/cart添加商品到购物车需登录GET/api/cart获取购物车列表需登录PUT/api/cart/:id修改购物车数量/勾选状态需登录DELETE/api/cart/:id删除购物车条目需登录POST/api/orders创建订单从购物车结算需登录GET/api/orders查看我的订单列表需登录GET/api/orders/:orderNo订单详情需登录PUT/api/orders/:orderNo/pay模拟支付需登录PUT/api/orders/:orderNo/confirm确认收货需登录RESTful 这层的设计原则一个资源一个路径方法表示动作一看路径就知道在操作什么对接前端时非常直觉。JWT 鉴权中间件是关键的一环它的逻辑是从请求头里取出Authorization: Bearer token解析并校验 token如果合法就把用户信息挂到req.user上后续控制器就能直接用不合法就直接返回 401。// middleware/authMiddleware.js const jwt require(jsonwebtoken); function authMiddleware(req, res, next) { const authHeader req.headers[authorization]; if (!authHeader) return res.status(401).json({ message: 未提供认证令牌 }); const token authHeader.split( )[1]; try { const decoded jwt.verify(token, process.env.JWT_SECRET); req.user decoded; next(); } catch (err) { return res.status(401).json({ message: 令牌无效或已过期 }); } }3.4 前端核心页面与状态管理实现前端的几个核心页面我逐个讲实现思路。首页商品列表核心逻辑是分页加载加下拉刷新我封装好api/product.js页面里用onMounted钩子触发首次加载用响应式数组存储商品列表。细节上注意商品卡片要显示原价和现价两个价格划线价用 CSS 的text-decoration: line-through这是电商页面最基础的视觉交互。商品搜索用防抖不然用户每敲一个字符就发一次请求后端压力大体验也很卡。实现思路是watch搜索关键词用setTimeout延迟 300ms 再发请求如果 300ms 内用户继续输入就清除计时器重新计时。购物车状态管理我用 Pinia它是 Vue 3 官方推荐的状态管理库。为什么购物车必须用全局状态因为购物车数据在多个页面共享——用户可能在商品详情页点“加入购物车”然后在导航栏看到角标数字变化这些都需要全局状态来同步。// stores/cartStore.js export const useCartStore defineStore(cart, { state: () ({ items: [], totalCount: 0, totalAmount: 0 }), actions: { async fetchCart() { const res await getCartApi(); this.items res.data; this.updateSummary(); }, async addToCart(productId, quantity) { await addToCartApi(productId, quantity); await this.fetchCart(); }, updateSummary() { const checkedItems this.items.filter(item item.checked); this.totalCount checkedItems.reduce((sum, item) sum item.quantity, 0); this.totalAmount checkedItems.reduce((sum, item) sum item.quantity * item.price, 0); } } });注意totalAmount的累加计算——item.quantity * item.price结果如果是浮点数可能有精度问题。解决方案是在后端返回价格时就把单位换算成分整数前端展示时再除以100。这比在前端用toFixed(2)靠谱得多因为toFixed是四舍五入可能出现 0.1 0.2 不等于 0.3 的精度问题。结算页面是流程中页面逻辑最复杂的一环用户选择收货地址、核对商品清单、填写备注、点击提交订单。提交后拿到后端返回的订单号跳转到支付页。支付逻辑做得最简单的是模拟支付——生成一个二维码或者直接一个“模拟支付成功”按钮点击后调后端的付款接口后端把订单状态改成“已付款”。接支付宝沙箱环境也好支付流程不变替换掉支付接口的第三方签名逻辑即可。3.5 后台管理界面与权限控制后台管理我单独做了一套界面入口跟商城分离。登录时后端会根据用户的role字段返回不同的身份标记前端路由守卫里判断如果用户角色不是管理员访问/admin开头的路径就直接重定向回商城首页。后台页面包含商品管理、分类管理、订单管理和统计面板。商品管理页面是核心表单和列表的典型 ERP 布局。商品表单有几个细节需要提醒。第一个是图片上传。用 Element Plus 的el-upload组件配置action为后端上传接口后端用 multer 处理并保存文件到uploads目录返回访问路径。注意上传接口需要做大小限制我这边限制单张 2MB格式只允许 jpg、png、webp不然用户传一个 GIF 动图网站直接被拖垮。第二个是库存联动。编辑商品时可以设置库存预警值当某个商品库存低于预警值时在订单管理和商品列表里都展示一个“低库存”的红色标记提醒管理员补货。在零食行业爆款断货就意味着流失真实订单这个提醒功能非常实用。3.6 订单流转逻辑与状态机设计订单流转是电商系统的核心业务逻辑状态变化一定要清晰。我把订单状态定义成一个常量枚举前端后端保持一致0待付款下单成功等待用户支付1待发货已支付等待商家发货2待收货已发货等待用户确认收货3已完成用户确认收货订单结束4已取消用户取消或超时未付款5退款中用户申请退款6已退款订单状态下发的核心逻辑是只有“待付款”的订单允许用户取消只有“已支付”且“待发货”的订单管理员才能发货只有“待收货”的订单用户才能确认收货。这些校验如果在前后端都做了才能把脏状态挡在前面。我遇到过离谱的情况用户在付款前狂点“提交订单”按钮结果后台生成了十几笔订单。解决方案有两个层面——前端提交订单时用标志位防重复提交按钮点击一次后进入 loading 不可点击后端在创建订单接口里对同一个用户做幂等校验比如 5 秒内不允许创建相同金额相同商品组合的订单。3.7 项目部署上线Nginx 配置与静态资源开发完成后上线部署又是一个独立的环节。流程大致如下。后端部署用pm2守护 Node.js 进程这是我用下来最稳的 Node 进程管理工具。启动命令pm2 start app.js --name shop-server它会自动拉起崩溃的进程开机自启也已经内置。前端部署运行npm run build把 Vue 项目打包成静态文件生成dist目录然后把它配置到 Nginx 下。Nginx 配置里有两个关键块一个是静态文件托管把dist目录指到根路径另一个是接口反向代理把/api开头的请求转发到 Node.js 服务。server { listen 80; server_name your-domain.com; root /var/www/shop-mall/dist; index index.html; location /api/ { proxy_pass http://127.0.0.1:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } # 前端路由用的 history 模式需要配置 location / { try_files $uri $uri/ /index.html; } }那个try_files配置很重要Vue Router 用了history模式地址栏没有#号时用户刷新当前页面Nginx 会按真实路径去找文件找不到就返回 404所以必须让它回退到index.html由前端路由接管。图片上传目录uploads需要单独配置静态访问路径否则商品详情页的图片全部加载不出来。可以给 uploads 单独加一个 location 配置指向后端的静态目录。4. 常见问题排查与开发经验实录4.1 高频环境报错与解决方案速查开发过程中会遇到很多看着很唬人、实际原因却很简单的报错这里整理一份速查表都是我实际踩过的。报错现象根本原因解决方案npm.ps1 无法加载系统禁止运行脚本PowerShell 执行策略限制管理员身份执行Set-ExecutionPolicy RemoteSigned -Scope CurrentUserError: Cannot find module express依赖未安装检查node_modules是否存在执行npm installEADDRINUSE: address already in use端口被占用换端口或lsof -i :3000macOS/Linux查占用进程后清理MySQL: Client does not support authentication protocolMySQL 8 默认认证插件与旧驱动不兼容创建用户时指定IDENTIFIED WITH mysql_native_password BY password前端请求接口报 CORS 错误跨域未配置或配置失效确认后端 cors 中间件是否挂载确认 Vite 代理是否生效Uncaught SyntaxError: Cannot use import statement outside a module引入模块语法与运行环境不匹配确认引入时带.vue或正确配置.js的 type 模块特别补充 MySQL 8 认证问题——这个问题在本地连接数据库时特别常见。mysql2 驱动新版其实已经解决这个问题如果你用的老版本或 Sequelize 版本过旧就会出现。我推荐无论如何给数据库建一个专门的应用账号顺手指定认证方式避免 root 裸奔也是安全习惯。4.2 购物车同步与并发扣库存的两场实战购物车前后端同步是我开发中改了三版才稳定下来的模块。第一版直接后端存储但未登录用户没法加购物车流失了很多体验。第二版全部本地存储登录后数据没法跨设备而且订单里没有购物车快照用户换个浏览器购物车就空了。第三版是线上稳定运行的方案——未登录用 localStorage登录后自动合并到后端以服务端数据为准。合并逻辑的思路是用户登录成功后把本地购物车的每个条目调后端“加入购物车”接口如果后端已有相同商品就累加数量合并完后清空本地购物车再刷新后端数据。并发扣库存的问题上我前面已经提过用事务加锁。这里补充一个运行体会——实际测试时用模拟并发工具同时发 50 个请求抢同一个库存为 5 的商品如果没有锁这 50 个请求可能全部成功下单库存变成负数加了事务和条件更新后只有 5 个请求成功其余的全部返回“库存不足”。这个差异直接关系到一个零食商城会不会在开业当天就超卖亏本。事务代码的简化写法是const conn await pool.getConnection(); try { await conn.beginTransaction(); const [rows] await conn.query( SELECT stock FROM product WHERE id ? FOR UPDATE, [productId] ); if (rows[0].stock quantity) { await conn.rollback(); return res.status(400).json({ message: 库存不足 }); } await conn.query( UPDATE product SET stock stock - ? WHERE id ?, [quantity, productId] ); // 插入订单和订单明细 await conn.commit(); } catch (err) { await conn.rollback(); throw err; } finally { conn.release(); }这里pool.getConnection()获取的是同一个连接事务必须基于同一条连接这个细节如果写错了比如每条语句都重新拿连接事务就不生效了改 bug 会改到怀疑人生。4.3 一个影响体验的细节商品图片与页面加载优化零食商城的商品详情页图片通常比较多每张图如果都是几 MB 的原图页面加载缓慢是必然的。我的优化思路是按尺寸裁三份列表页缩略图、详情页中图、放大高清图分别存储不同尺寸的图片前端按场景加载对应尺寸。这个方案不需要引入第三方图片处理服务后端上传接口里用 sharp 库统一处理一行命令生成不同尺寸的版本然后存到对应目录数据库里记录三份 URL。购物车渲染大量商品时注意给v-for加上:key用商品 ID 而不是数组下标否则删除中间条目时会导致组件状态错乱。这个 bug 我印象很深不加 key 的时候删除购物车第二个商品第三个商品的勾选状态会莫名其妙变成第二个商品的状态。另一个优化是路由懒加载。商城页面多如果首屏把几个页面都打进去白屏时间会很长。用() import(...)语法把路由组件变成异步加载配合 Nginx 的 gzip 压缩首屏体感流畅很多。4.4 上线前后的检查清单项目上线前我建议按这个清单逐一确认这些都是用实际损失换来的教训。环境变量里不要硬编码数据库密码和 JWT 密钥一律放到.env文件并加入.gitignore后端接口统一返回格式至少包含code、message、data三个字段前端 axios 拦截器统一处理避免每个页面各自处理错误订单金额相关校验后端必须做一遍——前端传过来的单价、总价一律不信任后端从数据库查真实价格来计算商品库存扣减后要检查数据库是否出现负数库存数据每周做一次核对备份策略要建立至少每天自动备份一次 MySQL 数据定期查看 pm2 日志及时发现后端异常关于接口统一返回这里多说一句。如果前端每个请求都要单独判断 2xx、4xx、5xx 再分别处理代码体量会呈现指数级膨胀。我在 axios 拦截器里统一处理 error toast比如 401 跳登录、400 弹提示每个页面的业务代码就只管成功态清爽很多。5. 项目打磨与可扩展方向系统跑通以后我建议再花一周做体验层面的打磨这会让整个项目从“能用的原型”变成“像样的产品”。用户端优先体验的是结算流畅度。排队检查购物车有没有选中项、库存够不够、地址是否齐全——任何一个环节不满足都不跳支付。每个跳转都给出明确的提示“请先选择商品再结算”。管理员端优先体验的是操作效率。批量上下架、批量改库存、订单备注和打印小票这些功能在零食这类高频补货、多 SKU 的场景下特别受用。如果商品数量上了几百个列表页的搜索和分类筛选体验是管理员每天面对的第一交互值得认真优化。技术层面可以加的能力包括接入真实支付网关、商品评论系统、优惠券模块、销售数据图表统计、小程序端。每个方向单独扩展的性价比都不错因为后端接口架构从一开始就按业务模块切开了——加模块是新表加新路由旧代码不会受影响。我个人最建议的下一步是接入订单物流跟踪零食类目用户对配送时效非常敏感订单状态里只要显示“已发货”用户就会天天来问物流单号。这个功能在订单表加一个物流公司和运单号字段再对接快递查询接口前后端的工作量都不大但用户体验提升非常明显。最后分享一个我在整个项目开发中最深刻的体会小项目做出来不难难的是把它打磨到“别人愿意用”的程度。这套零食商城系统从架构设计到落地核心目标一直是“真实可用”四个字——库存不超卖、订单不丢失、金额不偏差、用户操作有反馈。你按这个标准去实现每一个功能整个系统自然就能立得住。无论是拿来交作业、面试讲项目还是真给小店跑生意这套 Node.js Vue 小零食商城都能成为拿得出手的完整作品。遇到具体问题卡壳了再回头看这篇文章对应的模块按我写的排查思路过一遍大部分坑都能避开。
返回列表