如何仅使用 window 对象检查 PaymentResponse 状态?
结论
不能只通过 window 对象查询某次 PaymentResponse 的支付状态。
window.PaymentRequest 只能用来判断浏览器是否提供了 Payment Request API。支付产生的 PaymentResponse 是 PaymentRequest.show() 返回的 Promise 解析结果,不会自动保存到 window。此外,PaymentResponse 也没有通用的 status 属性。
原因
典型的支付调用如下:
const request = new PaymentRequest(methodData, details, options);
const response = await request.show();
这里的 response 只存在于支付代码的作用域中。除非代码主动将它暴露出来,否则其他代码无法通过下面的方式获取它:
window.PaymentResponse
即使浏览器中存在 window.PaymentResponse,它通常也只是接口构造器,不是某次支付产生的响应实例,其中也没有最近一次支付的状态。
PaymentResponse 主要提供以下数据:
response.requestId
response.methodName
response.details
response.payerName
response.payerEmail
response.payerPhone
response.shippingAddress
这些数据中没有标准的 response.status。而且,获得 PaymentResponse 只能说明用户完成了支付界面的交互,不代表资金一定已经扣款成功。最终支付结果通常要由支付服务商或业务后端确认。
有权修改支付代码时的处理方式
支付代码获得 PaymentResponse 后,应调用后端接口确认支付,并自行记录或广播结果:
async function startPayment() {
const request = new PaymentRequest(methodData, details, options);
const response = await request.show();
try {
const result = await fetch("/api/payments/confirm", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
requestId: response.requestId,
methodName: response.methodName,
details: response.details
})
}).then(res => res.json());
const status = result.success ? "success" : "fail";
await response.complete(status);
window.dispatchEvent(
new CustomEvent("payment-status", {
detail: {
requestId: response.requestId,
status
}
})
);
} catch (error) {
await response.complete("fail");
window.dispatchEvent(
new CustomEvent("payment-status", {
detail: {
requestId: response.requestId,
status: "fail"
}
})
);
}
}
页面中的其他代码可以监听这个自定义事件:
window.addEventListener("payment-status", event => {
console.log(event.detail.requestId);
console.log(event.detail.status);
});
支付代码也可以明确将结果写入全局变量:
window.paymentState = {
requestId: response.requestId,
status: "success"
};
不过,这属于应用自行实现的状态管理,并不是 Payment Request API 自动提供的功能。
无法访问支付代码时怎么办
如果支付代码没有暴露响应对象、派发事件或提供查询接口,就无法只依靠 window 获取可靠的支付状态。通常可以采用以下办法:
- 调用业务后端的订单状态查询接口。
- 根据订单号向支付服务端查询结果。
- 请支付模块增加回调、自定义事件或共享状态。
- 如果支付发生在 iframe 中,让 iframe 通过
postMessage()主动通知父页面。
父页面可以这样接收消息:
window.addEventListener("message", event => {
if (event.origin !== "https://payment.example.com") {
return;
}
if (event.data?.type === "payment-status") {
console.log(event.data.status);
}
});
这种方式要求支付页面已经实现对应的 postMessage() 发送逻辑,并且双方约定好消息格式。
注意事项
response.complete("success") 主要用于通知浏览器关闭或更新支付界面,不能作为资金结算成功的权威证明。可靠的支付状态应以服务端确认结果为准,例如支付网关回调、订单查询接口或服务端保存的订单状态。
在特定条件下,修改 PaymentRequest.prototype.show 或许可以拦截响应,但代码必须同源、位于同一个 JavaScript Realm,并在正确的时机执行。这种方式容易失效,也可能干扰正常的支付流程,不适合在生产环境中用于判断支付状态。
备注:内容仅供参考。