尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

农产品商城微服务架构:SpringBoot+SpringCloud全栈设计与实践

农产品商城微服务架构:SpringBoot+SpringCloud全栈设计与实践 这个项目做完之后我最大的感触是如果只看商城两个字很多人第一反应是单体就够用甚至一个后端服务加一个管理后台就行。但当你真正处理农产品这个品类时会发现订单、库存、营销、溯源、物流这些模块的诉求完全不一样改动频率和发布节奏也完全不同。这也是为什么我最终选择了SpringBoot SpringCloud微服务来支撑后端用Vue做管理后台、微信小程序做C端售卖端的组合。这篇文章就把整个项目的设计与实现过程梳理一遍包括为什么这么拆、每个服务怎么落地、小程序端怎么对接、部署时有哪些坑希望能给正在做类似选题或真实业务的人一些参考。1. 农产品商城的业务特点决定了架构不能拍脑袋1.1 农产品和标品电商看着像骨子里不一样做技术的人容易犯一个毛病看到商城两个字就往通用电商模板上靠用户表、商品表、订单表、购物车表一建觉得系统已经完成了一半。但农产品的业务模型和标品电商差距非常大至少在下面几个维度上会直接逼你改表结构、改接口、改流程商品粒度复杂。一个西红柿可以按产地分、按规格分大果、中果、小果、按批次分同一商品不同批次可能进价不同、库存不同、检测报告不同。标品电商那种一个SPU下面几个SKU的模型能做但会很勉强。价格不是常量。产地直供模式里价格受行情波动、当日供需、活动补贴影响经常要支持今日价秒杀价会员价多层价格策略。价格逻辑如果和商品基础信息绑死在同一张表里每次调价都要全表更新很痛。履约链路区域化。农产品销售不只是发货到家还可能包含产地直发、同城配送、社区自提点、冷藏周转仓等。订单生成后后续要派单给供应商、配送站还要记录冷链节点温度。溯源是信任核心。消费者买农产品尤其高单价的水果、肉禽很在意这东西从哪来、有没有检测报告。溯源数据要和订单关联、要能展示在小程序端这又是一个独立领域。说白了这个系统不是一个简单的交易网站而是商品管理 交易 营销 履约 溯源的复合系统。模块之间的逻辑复杂度、变更频率、数据私有关联度都很高这为后面选择微服务拆分埋下了伏笔。1.2 单体不是跑不动而是改不动说句公道话以大部分农贸商城的日订单量单体架构完全跑得动。数据库连接池撑个几千并发不难。真正的瓶颈不在性能而在维护性和发布效率。单体系统里商品团队要改价格策略订单团队要改售后流程市场团队要加秒杀活动这些代码可能散落在同一个工程里改一个地方就要把整个应用重测一遍。而且只要某个模块出现内存泄漏或线程阻塞整个商城都不可用这叫爆炸半径太大。微服务的好处不是把系统变快而是把系统拆成负责人明确的小单元。订单服务挂了商品浏览和秒杀还能继续营销服务要发布新活动不需要把支付服务一起重启。尤其是团队里有多个开发同时推进时服务边界清晰能省掉大量沟通和冲突成本。但也必须诚实微服务不是银弹。对于一个三个人团队、一个月交付的项目硬拆八个服务可能反而把自己拖垮。所以我在设计之前列了一个判断表符合两条以上才考虑单独拆服务判断维度单体方案的表现拆成微服务的收益模块是否被多个前端入口使用所有端共用一个接口层耦合重各自端按服务聚合变更隔离模块改动频率商品/营销几乎每周改独立发布互不阻塞是否有多角色团队并行同一代码仓库互相踩按业务域分仓库分服务是否有独立扩缩容诉求整体部署无法单独扩容高负载服务单独扩容是否有独立数据生命周期共用库字段含义互相污染每个服务私有库责任清晰农产品商城这条业务链路里商品营销价格是一个高频繁改动的域订单支付履约是一个对一致性和可靠性要求极高的域用户会员会话是一个相对稳定但访问量大的域溯源是一个独立且数据来源多样的域。每一条都指向拆分。1.3 我最终划分出的服务边界与数据边界拆分服务最容易犯的错是按页面拆比如把首页服务购物车服务我的服务拆出来这种拆法毫无意义。真正的拆分要按业务能力和数据内聚来划分。我最终确定的边界是这样的user-service用户、会员等级、收货地址、认证授权信息不包括微信登录的 code 换取逻辑那个放在网关层做。product-service商品类目、SPU/SKU、规格批次、库存流水、价格策略。这个服务是最庞杂的一个因为农产品商品模型复杂。order-service购物车、订单主流程、订单状态流转、售后单。payment-service支付渠道、支付单、退款单所有和微信支付/其他渠道打交道的都在这里。marketing-service优惠券、拼团活动、限时秒杀、积分。logistics-service发货单、物流轨迹、自提点分配、配送节点。trace-service溯源批次、检测报告、生产记录这个服务数据来源很多包括后台录入和供应商导入。gateway统一入口、路由转发、鉴权、限流。与之配套的是数据库的设计原则每个服务至少独立一个库绝不跨服务直接访问对方的表。比如订单表里有商品快照这个快照字段是从商品服务同步过来的冗余数据而不是每次下单实时去查询商品表。这样设计虽然带来了数据冗余和同步复杂度但换取了服务之间彻底解耦线上出问题时可以各自回滚不会因为一条 SQL 把两个服务拖死。服务间通信也做了区分需要同步返回结果的调用比如下单前校验库存用 OpenFeign不需要立即知道结果的比如支付成功后通知订单服务改状态用消息队列异步解耦。这个原则在后面订单链路里具体体现。2. SpringCloud组件选型不是用得越多越高级2.1 这些组件真正被用上的只有六七个SpringCloud 全家桶组件非常多但从零搭建这个项目时我刻意做了克制。网上很多教程喜欢把注册中心、配置中心、网关、熔断、限流、链路追踪、消息总线、分布式事务全塞进去结果光配置就写了几百行部署环境还要额外起四五个中间件项目本身反而没写多少业务代码。我的最终选型是这样的组件用途是否必须Nacos注册中心 配置中心必须拆服务后服务发现是刚需Spring Cloud Gateway统一网关路由校验鉴权必须不经过网关的微服务等于裸奔OpenFeign服务间同步调用必须拆了服务就得用Sentinel接口限流、熔断降级建议秒杀和高峰流量靠它兜底Seata分布式事务可选我只在极少数强一致场景用Sleuth Zipkin链路追踪建议排查跨服务问题必备RocketMQ异步解耦、削峰、最终一致性必须支付回调和订单状态变更靠它Nacos 选它的原因很直接它同时干注册中心和配置中心两件事中文文档和社区案例多遇到问题基本都能搜到。早期版本有人诟病它 AP/CP 模式切换复杂但对这个项目来说用默认的 AP 模式服务发现就够了。配置中心的好处是每个服务连接 Redis、MQ、数据库的参数可以从配置文件集中管控改完不用重新打包上线Nacos 会推送刷新。有一个小建议如果你的团队以前没接触过微服务第一步先把注册中心网关两个业务服务跑通再逐步加 Sentinel、Seata 这些高级组件。一次到位往往意味着一次线上事故。2.2 管理后台用Vue、C端用小程序是场景决定的这个项目的两端产品形态差异其实很大所以我没有尝试一套代码到处运行的激进方案。管理后台的核心需求是复杂表格、多条件筛选、数据统计、商品上下架、价格调整、优惠券配置、溯源信息录入用户是运营和客服使用场景是固定电脑和浏览器。这种场景下 Vue 生态非常合适Vue 3 TypeScript Element Plus Pinia Vite组合式 API 写业务逻辑很顺手Element Plus 的表单和表格组件能直接覆盖大部分后台诉求。C端小程序则完全不一样。农产品的购买入口大量来自微信社群、朋友圈转发、拼团接龙用户在微信里点开链接就能完成购买这是 H5 很难替代的场景。微信小程序除了入口方便还天然提供登录、支付、订阅消息能力。虽然 H5 也可以调起微信支付但整体体验和转化率不如小程序。小程序端我选了原生开发没有上 Uniapp。原因是这个商城的 C 端页面不算多首页、分类、购物车、订单、我的五个 Tab 就构成了主体原生 WXML 开发调试更直接。如果以后要发布到支付宝小程序、抖音小程序再迁移到 Uniapp 也不迟因为接口层已经统一走网关前端框架只是皮。2.3 版本搭配和基础中间件版本搭配是微服务项目第一个隐藏的大坑。SpringCloud 和 SpringCloud Alibaba 各版本之间有严格的对应关系不对应就会出现依赖冲突或者组件无法注入。我整理了两条可行的路线稳妥路线Spring Boot 2.7.x Spring Cloud 2021.x Spring Cloud Alibaba 2021.0.x JDK 8。这套组合在网上的资料最多很多生产项目还在用踩坑容易搜到答案。升级路线Spring Boot 3.2.x Spring Cloud 2023.x Spring Cloud Alibaba 2023.x JDK 17。新项目可以考虑但注意部分旧版依赖不支持。我这里选的是稳妥路线。不是说新版本不好而是交付项目时间紧张稳定优先。另外建议整个项目用 Maven 的 BOMBill of Materials统一管理依赖版本父 pom 里锁死 SpringCloud 和 Alibaba 的版本号子服务不需要再单独指定避免某个子服务引入一个高版本依赖把全局弄崩。中间件层面MySQL 8.0 存核心交易数据Redis 做缓存、分布式锁、秒杀预扣库存RocketMQ 负责异步消息。Redis 的使用要提前规划好 key 前缀比如商品缓存product:info:{skuId}库存product:stock:{skuId}会话user:token:{token}这样排查问题和清理缓存时才能精准操作不会误删业务数据。3. 后端核心实现骨架、统一响应、网关鉴权与订单状态机3.1 多模块工程拆法把接口定义和业务实现分开后端工程结构我采用 Maven 多模块管理。很多人第一次做微服务时容易把 Feign 接口定义直接写在调用方服务里导致服务间产生循环依赖。为了避免这个问题我把所有 Feign 接口单独放在一个mall-api模块里任何服务都可以依赖它但不会因为接口定义产生双方互引。mall-agriculture-parent ├── mall-common # 统一返回体、全局异常、常用工具类 ├── mall-gateway # 网关服务 ├── mall-api # Feign接口定义、DTO对象 ├── mall-modules │ ├── user-service │ ├── product-service │ ├── order-service │ ├── payment-service │ ├── marketing-service │ └── logistics-servicemall-common里的统一返回体是前后端联调的基础。这个类看起来简单但几乎所有接口都依赖它一开始必须定清楚public class ResultT { private Integer code; // 20000 成功非20000 失败 private String message; // 提示信息 private T data; // 数据体 public static T ResultT ok(T data) { ResultT r new Result(); r.code 20000; r.message success; r.data data; return r; } public static T ResultT fail(String message) { ResultT r new Result(); r.code 50000; r.message message; return r; } }配合RestControllerAdvice做全局异常捕获业务代码里只需要抛业务异常由统一异常处理器转换成 Result 返回避免每个接口都写try/catch。前端也可以只在请求封装层统一判断code不用每个页面各自处理错误逻辑。3.2 网关层的路由、鉴权和限流网关是这个系统所有流量的总入口。小程序端、Vue 管理后台的所有请求都先打到这里再按路径前缀转发到对应服务。路径前缀我做了一个约定/api/admin/**转发到管理后台相关服务要求管理员权限/api/wx/**转发到小程序端相关服务要求普通用户登录/api/public/**允许匿名访问比如商品列表、轮播图、公告网关配置核心部分大致如下spring: cloud: gateway: routes: - id: product-service uri: lb://product-service predicates: - Path/api/wx/product/**,/api/admin/product/**,/api/public/product/** - id: order-service uri: lb://order-service predicates: - Path/api/wx/order/**,/api/admin/order/** - id: user-service uri: lb://user-service predicates: - Path/api/wx/user/**,/api/admin/user/**网关里我做两件业务相关的事情JWT 鉴权和基础限流。所有非/api/public/**的请求先解析 token把用户 ID、角色信息解析出来放到请求头里再转发给下游服务。下游服务不再关心 token 怎么解析、session 怎么校验直接从请求头拿用户信息这是一个很实用的设计。限流我用 Sentinel 做了网关级别的规则比如某商品详情接口每秒钟最多放行多少请求超出直接返回系统繁忙。秒杀活动时这个规则非常重要它能把压力挡在网关之外保护后端的商品服务和订单服务不至于被打挂。但注意网关不要做太重的事情比如不要在网关里查询数据库、做复杂的业务校验否则网关反而会变成新的瓶颈。3.3 商品与库存缓存预检 数据库乐观锁兜底农产品商品信息变化频繁频繁查数据库不现实。商品详情、首页推荐这些读多写少的数据放 Redis 缓存配合缓存过期策略。但库存不能只靠缓存因为它是强一致数据。下单减库存的核心逻辑是这样的用户提交订单order-service 通过 Feign 调用 product-service 的校验库存接口。product-service 先查 Redis 库存如果库存不足直接返回失败减少无效 DB 请求。通过缓存校验后执行数据库扣减使用乐观锁防止超卖UPDATE product_sku_stock SET stock stock - #{num} WHERE sku_id #{skuId} AND stock #{num}stock #{num}这个条件很关键如果库存已经被别人扣完这个 SQL 的受影响行数为 0程序检查到影响行数为 0 就知道扣减失败然后回滚订单。这种方式不需要给整行数据加锁是并发扣库存最常采用的方案。扣减成功后库存变更通过 MQ 发送一条消息异步更新 Redis 缓存中的库存数字。这里不要等数据库事务提交后再同步更新 Redis而是采用先更新缓存、再发消息、最终由数据库流水做对账的方式。这样即使消息丢失只要第二天做个对账任务扫描数据库流水修正缓存即可不至于超卖。3.4 支付回调与订单状态机把强一致变最终一致支付环节最常见的错误是把支付回调里要做的事情都在回调接口里同步完成更新支付单、更新订单状态、扣减库存、发短信。回调一旦处理超时微信会重复调用接口没有幂等保护就会出现重复发货、重复发券。我的做法是把支付回调做成轻量入口payment-service 收到微信支付回调先校验签名确认支付金额和订单号对应。更新支付单状态为已支付然后立刻给微信返回成功响应告诉微信我已经收到了。payment-service 向 MQ 发一条支付成功消息。order-service 消费消息更新订单状态为已支付再发消息触发物流服务创建配送单、触发营销服务发放积分。通过消息队列把一次回调拆成了多个异步步骤每个步骤都能单独重试。消费者里做幂等消息里带orderId和eventId处理前先查本地表是否已经处理过这个事件处理过就直接返回不会重复执行。订单状态流转我设计成明确的状态机待支付 - 已支付 - 配货中 - 已发货 - 已完成中间分支有已取消、退款中、已退款。状态变更的 SQL 语句都要带上当前状态条件比如从待支付变已取消的 SQL 必须写WHERE order_id ? AND status 待支付。这样能避免用户同时操作取消订单和管理员误发货时后写的状态把先写的覆盖掉。4. 小程序端设计与实现不只是套一个模板4.1 页面骨架与农产品商城的特色设计小程序的页面框架走的是经典 TabBar 五页面首页、分类、购物车、订单、我的。但针对农产品这个品类首页不能做成普通电商的简单 Banner 商品瀑布流那样没有辨识度。首页我加了这几个模块产地直供推荐、今日秒杀、农产品溯源检测入口、热门产地标签。特别是溯源检测入口点进商品详情页就能看到该批次的产地、采摘日期、检测报告这个功能对建立信任感帮助极大。后端对应的就是 trace-service 提供的溯源数据接口商品详情页通过skuId或者batchNo查询。页面布局上因为要展示大量商品图片和溯源证书图图片压缩很关键。管理后台在商品上传时就把图片压缩成多尺寸缩略图、列表图、详情图小程序端按场景加载对应尺寸避免首屏加载一堆原图导致白屏时间过长。4.2 列表滚动加载与防重复请求小程序页面列表加载更多是网上问得非常多的问题这个项目的首页商品推荐、分类页商品列表、订单列表都会用到。核心逻辑是onReachBottom触发下一页加载但必须加锁防重。Page({ data: { list: [], page: 1, pageSize: 10, hasMore: true, loading: false }, onReachBottom() { if (this.data.loading || !this.data.hasMore) return; this.loadMore(); }, async loadMore() { this.setData({ loading: true }); try { const res await request({ url: /api/wx/product/list, data: { page: this.data.page, pageSize: this.data.pageSize } }); const list this.data.list.concat(res.data.records); this.setData({ list, page: this.data.page 1, hasMore: res.data.current res.data.pages }); } finally { this.setData({ loading: false }); } } })loading这个标志位是防止用户快速滚动时连续触发多个请求。hasMore的判断用分页接口返回的current pages比records.length pageSize更可靠。加载完成后展示已经在底部或没有更多了的提示这个小细节能明显改善用户体验。4.3 微信登录、request 封装与支付对接小程序登录我采用静默登录方案用户打开小程序时调用wx.login拿到临时code发给后端后端用 code 向微信接口换取openid生成自己的token返回给小程序。之后所有请求在 header 里带上 token。const request (options) { return new Promise((resolve, reject) { wx.request({ url: baseUrl options.url, method: options.method || GET, data: options.data || {}, header: { Content-Type: application/json, X-Access-Token: wx.getStorageSync(token) || }, success(res) { if (res.data.code 20000) { resolve(res.data.data); } else if (res.data.code 40100) { // token 过期重新静默登录后再请求 reloginAndRetry(options).then(resolve).catch(reject); } else { wx.showToast({ title: res.data.message, icon: none }); reject(res.data); } }, fail(err) { reject(err); } }); }); };注意 401 的处理逻辑。用户使用到一半 token 过期是常见情况不能把用户一脚踢回登录页尤其农产品商城的很多用户是中老年群体让他们重新授权一次很容易直接放弃下单。这里我在 401 时自动重新登录并重放原请求用户基本无感知。支付流程是前端调wx.requestPayment所需参数由后端统一下单接口返回timeStamp: 时间戳 nonceStr: 随机字符串 package: prepay_idxxx signType: RSA/MD5 paySign: 签名这里有个经验用户调起支付后哪怕微信返回支付成功也不要立刻在前端页面展示已支付。微信支付的回调是异步的以后端确认支付成功再更新订单状态为准。所以支付成功跳转后页面应该轮询订单状态接口每 2 秒查一次最多查十次拿到已支付状态后再展示成功页。这样能避免用户支付成功但网络回调延迟时页面显示待支付造成的恐慌和重复提交。5. 从本地到服务器双端联调与部署的完整链路5.1 本地联调的跨域与代理设置微服务项目本地联调比单体麻烦很多因为浏览器或小程序直接访问多个服务端口肯定有跨域问题。我的做法是统一走网关。Vue 管理后台在本地开发时用 Vite 的 proxy 代理把所有/api请求转到网关地址浏览器看到的始终是同源的自然没有跨域问题。// vite.config.js export default { server: { port: 3000, proxy: { /api: { target: http://localhost:8080, // 网关地址 changeOrigin: true } } } }小程序端本地调试更方便微信开发者工具可以在详情 - 本地设置里勾选不校验合法域名这样就能直接请求http://localhost:8080。但注意这个做法只在开发环境有效真机预览和正式发布时必须配置https合法域名否则请求会被微信拦截。联调时建议给小程序端和管理后台分配不同的接口前缀/api/wx/**和/api/admin/**这样网关能区分入口做不同权限校验前端团队也能在日志里快速分清楚请求来自哪个端。5.2 Docker Compose别在一台服务器上手动跑八个 jar项目部署时最痛苦的事情就是运维要手动启动八个服务每个人启动顺序不一样Nacos 还没就绪业务服务就启动结果服务注册不上排查半天。所以我把整套后端环境用 Docker Compose 编排一条命令启动所有依赖。services: mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: root123 volumes: - ./mysql/data:/var/lib/mysql redis: image: redis:7-alpine ports: - 6379:6379 rocketmq: image: apache/rocketmq:5.1 nacos: image: nacos/nacos-server:v2.2.3 environment: MODE: standalone ports: - 8848:8848 - 9848:9848 gateway: build: ./mall-gateway depends_on: - nacos ports: - 8080:8080 product-service: build: ./mall-modules/product-service depends_on: - nacos - mysql - redis这里有一个关键配置服务之间互相调用不能再用localhost因为每个容器是独立的网络命名空间。要让业务服务注册到 Nacos 时使用容器内网地址比如nacos容器名和product-service容器名就是它在 Docker 内网里的 hostname。如果写成localhost:8848容器里找不到 Nacos服务会一直注册失败。5.3 Nginx 反向代理与微信小程序对 HTTPS 的硬要求小程序正式环境有一个强制要求所有接口请求必须是 HTTPS并且域名要在小程序后台配置为request合法域名。这意味着服务器上光有服务和数据库不够还要有一个入口做 HTTPS 终结。我的做法是在最前面加一层 Nginx配置大概如下server { listen 443 ssl; server_name api.example.com; ssl_certificate /etc/nginx/ssl/api.example.com.pem; ssl_certificate_key /etc/nginx/ssl/api.example.com.key; location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }管理后台的静态文件则由另一个 Nginx server 块提供服务Vue 打包后的dist目录直接指向站点根目录。管理后台也做成 HTTPS魔法上避免浏览器地址栏的不安全提示影响运营同事使用。部署上线前我踩过的几个比较典型的坑整理成表格现象原因解决办法Nacos 服务列表里服务时有时无服务器内存不足Nacos 被 OOM 杀掉给 Nacos 单独限制堆内存别开默认最大值服务启动报配置中心加载失败Nacos 配置未创建或 namespace 不对先通过控制台创建好配置再启动服务小程序真机请求全部失败没配置合法域名或证书不完整检查证书链是否完整域名是否备案Redis 连接数被占满每个服务连接池配置过大八个服务叠加统一限制max-active、max-idle空闲超时调短6. 经验复盘微服务项目最容易翻车的三个决策点6.1 分布式事务别硬上能异步就异步刚做微服务的人第一反应往往是跨服务更新数据必须分布式事务于是引入 Seata 的 AT 模式把下单、扣库存、生成履约单包进一个全局事务。但全局事务有代价事务范围越大锁持有的时间越长并发性能越差而且任何一个参与方网络抖动整个事务就要回滚用户体验极差。我的建议是把强一致的需求先梳理一遍能通过业务设计转成最终一致的尽量转成最终一致。比如下单扣库存其实并不需要订单服务和商品服务在同一个数据库事务里。完全可以先扣库存本地事务扣成功再创建订单另一个本地事务创建订单失败发消息冲正库存。虽然有一个短暂的时间窗口可能出现库存扣了但订单没建但通过消息队列的重试和补偿机制最终会收敛到正确状态。对商城这种业务来说最终一致完全够用用户不会感知到中间状态。Seata 只在极少数真正需要强一致的场景用比如用户余额扣减 积分增加这种同一账户体系内绝对不能出现一边成功一边失败的操作。其他地方优先考虑状态机 消息 对账任务。6.2 版本依赖要锁定别信网上的老配置SpringBoot、SpringCloud、SpringCloud Alibaba 三者之间的版本对应严格到让人抓狂。网上很多文章年代久远照着复制下来SpringCloud 2021 的依赖配到 Spring Boot 3.2 上直接项目起不来报错还千奇百怪。建议项目一开始就在父 pom 里用官方 BOM 锁版本dependencyManagement dependencies dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-dependencies/artifactId version2021.0.8/version typepom/type scopeimport/scope /dependency dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-alibaba-dependencies/artifactId version2021.0.5.0/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement只要版本锁死后面加任何依赖都先检查有没有同组件不同版本的冲突。被最坑的一次是子服务单独引入了高版本的 hutool它传递依赖的某个包和 SpringCloud 组件冲突导致网关路由一直不生效查了整整半天。6.3 小程序的体验优化比后端更影响成单率很多做后端出身的人容易忽视小程序端的体验觉得接口通、页面能点就算完成。但实际上在农产品消费场景里用户往往是四五十岁的群体页面响应稍慢、操作步骤多了转化率掉得很明显。几个我后来专门补的优化点商品第一屏只加载轮播图和价格信息详情大图用懒加载不要所有图片一次性请求。购物车图标上的角标数字要本地实时更新不用等接口刷新。下单页的默认地址要自动填充最新使用过的地址不要让用户重新选。把显示商品产地、检测报告、物流节点放在显眼位置这类信息能显著降低售后咨询量。针对长列表分页大小设为 10 到 15 条太多会卡太少用户不停滑动触发请求反而更耗流量。小程序端还有一个容易被忽略的问题接口请求失败时不要只弹 toast要区分网络失败可以重试和服务异常请联系客服给出对应的操作按钮。老年人用户遇到报错经常会直接退出小程序我们要尽量把错误页面做得更友好。说实话把微服务完整跑通并不难真正难的是让每个环节都能被运维、测试和运营同事理解。后端接口规范、网关路由规则、订单状态机、小程序请求封装每一块都要有文档和日志可查。架构不是炫技它是为了回答明天上线谁负责、出故障影响多大、改需求多久能发版这些问题。如果你也正在做一个类似的商城类项目在纠结要不要拆微服务我的建议是先把业务边界和状态流转图画清楚再决定技术栈会少走很多弯路。
返回列表