微信小程序支付成功但页面没变:我把订单状态机、轮询和超时兜底补齐
支付回调成功不等于前端页面能立刻拿到结果。我用订单状态机、主动查询轮询和超时降级,把微信小程序支付后的状态同步补齐。

作者
ZHOUYI
这个问题出现在一个小程序下单流程里:用户付完款,微信支付弹窗已经显示成功,但页面仍停在“待支付”。刷新一下或重新进入订单列表,状态又变成已支付。排查后发现不是支付没成功,而是前端把 wx.requestPayment 的 success 当成了最终结果。实际上,服务端回调可能晚几秒,也可能因为重试、网关抖动而更慢,前端必须补齐状态同步。
先把订单状态机收口
我把订单状态收敛成待支付、支付中、已支付、已取消、已退款。前端不再在支付弹窗成功后直接跳“支付完成”,而是先进入支付中,再请求服务端订单状态接口。服务端也不只依赖回调,回调到达时更新状态,前端查询时也会主动调用微信查单接口做二次确认。这样状态来源统一,页面跳转才有依据。
用轮询补齐回调延迟
- 支付成功后,前端将本地状态切到支付中。
- 立即查询一次服务端订单状态。
- 如果仍是支付中,按 1s、2s、3s 的间隔继续查询。
- 查到已支付就进入结果页,查到失败就引导重新支付。
超时兜底与失败降级
轮询必须有上限,否则页面会一直转圈。我设置最多查询 5 次,超时后不再假装等待,而是展示“支付处理中,请稍后查看订单”,并提供订单号、刷新按钮和订单入口。这样即使回调延迟、用户网络差,或者中途杀掉小程序,也能给用户一个明确出口,减少客诉。
const pollOrder = async (orderId, times = 5) => {
for (let i = 0; i < times; i++) {
const res = await fetchOrder(orderId);
if (res.status === 'PAID') return res;
if (res.status === 'FAILED') throw new Error('支付失败');
await sleep(1000 * (i + 1));
}
return { status: 'PENDING' };
};“前端拿到的支付成功只是流程开始,服务端确认后的订单状态才是事实。”
补完状态机、轮询和超时兜底后,支付成功但页面不变的问题基本消失。更重要的是,用户知道当前处于哪一步,失败时也有明确降级路径。支付系统不怕慢,怕的是前端、服务端和回调各说各话;把状态流收口,体验才会稳。