网络慢时客户连续点击下单,出现两张订单或两次支付。只给按钮加disabled不够,因为重试、浏览器回放和网关回调仍可重复到达。
处理步骤
步骤1:对重复订单比较customer/guest、quote_id、支付transaction_id、remote_ip和created_at。相同Quote产生两单说明订单提交并发保护失效;不同Quote则先查前端是否重复创建购物车。
步骤2:前端在placeOrder Promise完成前禁用按钮并显示进度,失败时按明确错误恢复;不要在timeout后自动无条件重发。
步骤3:服务端以cart_id加支付attempt_id生成幂等键,在提交前原子占用。相同键再次到达时返回原订单结果,不再次调用网关。数据库要有唯一约束或可靠锁,不能只用进程内变量。
步骤4:支付回调按网关transaction_id幂等处理;创建Invoice、发送邮件和扣库存前检查是否已完成。已有重复单逐单核对支付后取消未付款单。
命令与数据检查
SELECT entity_id,increment_id,quote_id,customer_email,created_at FROM sales_order WHERE quote_id=:quote_id ORDER BY entity_id;
SELECT payment_id,txn_id,txn_type,created_at FROM sales_payment_transaction WHERE order_id IN (:order_ids);上线前验证
使用浏览器双击、两个并发请求、客户端超时重试和重复Webhook测试,最终只能有一张订单、一次capture和一次库存扣减。
不要通过关闭客户重试来掩盖问题;幂等返回应让客户能拿到已经创建的订单号。

