必须依赖后端查单接口确认支付状态,因uni.requestPayment的success仅表示拉起支付界面成功,不保证实际支付完成;需定时调用后端订单查询接口(传out_trade_no),轮询最多15次,根据status字段(如SUCCESS/NOTPAY)终止或提示,并适配多平台验签与查询。

不能靠前端轮询猜,必须后端提供查单接口,否则你永远不知道用户到底付没付成功。
为什么 uni.requestPayment 的 success 不代表支付成功
很多人误以为 uni.requestPayment 的 success 回调一触发,订单就“已支付”。这是错的——它只代表微信客户端拉起了支付界面、用户点了确认、且本地签名校验通过。但网络可能中断、用户中途退出、甚至微信服务器返回失败而前端根本收不到回调。
- 用户扫码后关掉页面 →
fail可能不触发(尤其 H5 环境) - 小程序里点支付,手机突然断网 →
success仍会执行,但后端压根没收到微信通知 - 微信异步通知(
notify_url)失败时,后端无法更新状态,前端若不主动查,就会一直显示“支付中”
必须依赖后端提供的订单查询接口
真正可靠的支付状态,只能由后端通过微信官方 API(如 unifiedorder 后调用 orderquery)或数据库订单状态字段返回。uni-app 前端要做的,是定时或按需请求这个接口。
- 接口通常需要参数:
out_trade_no(你生成的订单号),少数场景还需transaction_id(微信返回的交易号) - 响应格式应包含明确状态字段,例如:
status: 'SUCCESS' | 'REFUND' | 'NOTPAY' | 'CLOSED' - 不要自己解析微信返回的 XML 或原始 JSON;让后端统一转换为前端友好的结构
轮询逻辑怎么写才不翻车
轮询不是无脑 setInterval,得控制次数、超时、取消时机,否则卡死或白屏。
- 最多轮询 10–15 次(即 15 秒),之后自动终止并提示“请稍后在订单页查看”
- 每次请求前检查订单当前状态,如果已是
SUCCESS或CLOSED,立刻clearInterval - H5 端注意:页面切后台时,
setInterval可能被浏览器节流,建议加 visibilitychange 监听,切回前台时重置计时器 - 小程序端可用
uni.showLoading配合遮罩,避免用户重复点击“立即支付”按钮
const timer = setInterval(async () => {
try {
const res = await queryOrderStatus({ out_trade_no: this.orderNo });
if (res.status === 'SUCCESS') {
clearInterval(timer);
uni.showToast({ title: '支付成功', icon: 'success' });
setTimeout(() => uni.navigateBack(), 1500);
} else if (res.status === 'NOTPAY' || res.status === 'USERPAYING') {
// 继续等
} else {
clearInterval(timer);
uni.showToast({ title: '支付异常,请查看订单详情', icon: 'none' });
}
} catch (e) {
clearInterval(timer);
console.error(e);
}
}, 1000);
苹果/华为/支付宝等渠道状态查询更不能省
这些平台没有统一的“前端回调保证”,尤其是苹果 IAP,requestPayment 成功后,必须把 receipt_data 发给服务端做 JWS 验签,再由服务端调 Apple 接口查真实状态。鸿蒙 IAP 还要处理补单(queryPurchases)和发货确认(finishPurchase)。
所有渠道都一样:前端只负责发起、等待、展示;状态判定权必须交给后端,且后端要对接各平台的官方查询 API。漏掉任意一环,都会导致用户付了钱却收不到服务。











