Magento 2 出现两笔内容相同、时间相近的订单,不能简单归因于用户点了两次。正常下单流程会对 Quote 状态做控制,但第三方支付、自定义 API、网络重试和错误的异常处理仍可能绕过保护。
先比较两笔订单
记录订单创建时间、quote_id、客户、商品、金额、支付方式和外部交易号。如果两笔订单来自不同 quote_id,可能是前端或接口创建了两个购物车;如果关联同一业务请求,则更像重复提交或并发。
前端按钮只能改善体验
点击 Place Order 后禁用按钮可以减少用户重复点击,但不能作为唯一防线。网络超时后浏览器、App 或网关都可能重试,服务端必须具备幂等能力。
支付回调会重复到达
支付服务商通常采用“至少一次”投递。你的回调接口返回超时或 500 时,同一通知会再次发送。处理前应使用支付交易号或事件 ID 检查是否已经完成。
if ($this->paymentEventRepository->exists($eventId)) {
return;
}
$this->transaction->addObject($eventRecord);
$this->paymentProcessor->process($payload);
$this->transaction->save();
幂等键必须有数据库唯一约束,不能只先查再写,否则两个并发请求仍可能同时通过检查。
自定义下单接口
为每次业务下单请求生成稳定的 request_id。客户端重试时继续使用同一个 ID,服务端返回已创建订单,而不是再次调用 CartManagement 创建新订单。
错误处理造成的假失败
订单已经写入数据库,但响应在邮件发送或外部同步阶段抛出异常,客户端会认为下单失败并再次提交。非关键后续任务应异步处理,不能让它们改变订单创建的最终响应。
修复前不要删除重复订单来掩盖问题。保留两笔订单和日志,按 quote_id、request_id、交易号重建时间线。找到重复发生在哪个边界,才能决定是前端防抖、回调幂等还是事务拆分。

