适合,但直接用 yii\rest\ActiveController 暴露商品接口会踩坑——因其仅支持基础 CRUD,无法处理库存扣减、状态流转、幂等控制等电商核心逻辑,需采用资源+行为混合设计,分控制器职责并手动实现缓存与并发控制。

适合,但直接用 yii\rest\ActiveController 暴露商品接口会踩坑——尤其是库存扣减、状态流转和并发控制这类电商核心逻辑。
为什么 ActiveController 不能直接用于商品下单/库存操作
它默认只做 CRUD 映射,不处理业务约束。比如 POST /products 创建商品没问题,但 POST /products/123/decrease-stock 这类操作它根本不识别,硬塞进 actions() 里又破坏 REST 语义。
- 所有方法都走
findModel()+save(),没法插入库存校验、幂等判断、事务包装 - 错误响应固定为
400 Bad Request或500,电商需要区分“库存不足”409 Conflict、“重复下单”400、“非法状态”422 Unprocessable Entity - 没内置幂等键(如
X-Idempotency-Key)支持,重试请求可能重复扣库存
商品接口该用什么结构:资源 + 行为混合设计
电商商品不是纯数据资源,它有行为(上架、下架、扣库存、审核)、有状态机(draft → onsale → offline)、有聚合边界(商品 + SKU + 库存 + 价格)。得放弃“一个控制器管到底”的思路。
- 主资源走 REST:用
ProductController处理GET /products、GET /products/123等只读场景 - 关键行为单独建控制器:比如
StockController处理POST /stock/decrease,接收{ "sku_id": "A001", "quantity": 2, "idempotency_key": "req_abc123" } - 状态变更走专用动作:在
ProductController里重写actionPublish(),内部调用ProductService::publish()做完整校验
urlManager 规则怎么配才不混乱
别全塞进一个 UrlRule。电商接口多版本、多入口(PC / H5 / App),硬写死规则后期改起来疼。
- 基础资源用自动规则:
['class' => 'yii\rest\UrlRule', 'controller' => 'product'] - 行为接口显式声明:
['pattern' => 'stock/decrease', 'route' => 'stock/decrease', 'verb' => 'POST'] - 版本前缀统一加在
rules数组最前面:['pattern' => 'v1/<action:>', 'route' => 'product/<action>']</action></action:> - 避免用
enableStrictParsing => true同时配大量自定义 pattern,会导致 404 难定位
缓存和并发必须手动补,框架不替你扛
ActiveController 的 cacheHeaders 只控制 HTTP 缓存头,对 Redis 缓存商品详情、库存数完全没用。而电商最怕缓存和 DB 不一致。
- 读商品详情时,先查 Redis(
product:123),未命中再查 DB + 写回缓存,设置合理过期时间(比如 10 分钟) - 扣库存必须用 Lua 脚本或数据库行锁:
UPDATE stock SET quantity = quantity - 2 WHERE sku_id = 'A001' AND quantity >= 2,检查影响行数是否为 1 - 不要依赖
yii\caching\Dependency自动失效——库存变化太频繁,依赖反而拖慢写操作
真正难的不是把商品列出来,而是保证每次“扣 1 件”都原子、可重试、可追溯。RESTful 是骨架,电商逻辑才是血肉,得一层层自己长上去。


















