iframe重定向:从父页面跳出并让父页面重定向
我在我的网站上使用ASP插件来接受信用卡支付:
https://wordpress.org/plugins/stripe-payments/
这个插件有一个简短码(shortcode),会显示一个按钮,点击后会打开一个弹出框,内容来自这个URL:
https://webfor99.com/asp-payment-box/?product_id=4095
https://snipboard.io/rkLZEc.jpg
当交易被批准或拒绝时,它会重定向到相应的“感谢页面”或“错误页面”。
不过,我需要在页面上直接解决方案(而不是按钮)。所以我把这个URL直接嵌入一个iframe到页面中。效果很好,唯一的问题是不会跳转到相应的“感谢页面”或“错误页面”(iframe和父页面都没有跳转)。请查看截图:
https://snipboard.io/UPQ9aM.jpg
https://snipboard.io/S4as0G.jpg
我需要让iframe的跳转能够跳出iframe,进入父页面并让父页面跳转到相应的“感谢页面”或“错误页面”。
我咨询了插件的支持开发者,他们建议我:
如果你想用iframe的方式进行自定义(例如跨域),你可以尝试让父页面监听来自iframe的
postMessage,并执行window.top.location.href = ...
于是我写了这段代码:
// Listen for messages from the iframe
window.addEventListener("message", function(event) {
// SECURITY: Verify the origin of the message
//if (event.origin !== "https://webfor99.com/asp-payment-box/?product_id=4095")
//return;
// Check if the message indicates a success/redirect
if (event.data && event.data.action === 'redirect') {
alert(event.data)
// Redirect the parent page to the new URL
window.top.location.href = event.data.url;
}
}, false);
然而,仍然无法让父页面跳转,我也已经没什么主意了。有没有多一个眼睛帮我看看?拜托,感谢!
解决方案
问题
你的父页面监听看起来没错,但问题很可能出在 iframe那边 —— iframe实际上并没有真正发送 postMessage。你只是监听,却没有发送消息。
完整解决方案
1.父页面(你的网站)
<script>
window.addEventListener("message", function(event) {
// SECURITY: Verify the origin
if (event.origin !== "https://webfor99.com") return;
if (event.data && event.data.action === "redirect") {
window.top.location.href = event.data.url;
}
}, false);
</script>
<iframe id="payment-frame" src="https://webfor99.com/asp-payment-box/?product_id=4095"></iframe>
2. iFrame内部(支付页面 — 如果你有访问权限)
iframe页面在交易成功/失败后必须 发送 消息:
// After payment success/failure, call this:
function redirectParent(url) {
window.parent.postMessage(
{ action: "redirect", url: url },
"https://your-parent-domain.com" // target origin for security
);
}
// Example usage:
// On success:
redirectParent("https://yoursite.com/thank-you");
// On error:
redirectParent("https://yoursite.com/error");
3.如果你没有iFrame来源的访问权限
由于这是一个第三方插件(webfor99.com),你很可能无法修改iframe。在这种情况下,改为在父页面轮询iframe的 URL:
const iframe = document.getElementById("payment-frame");
const checkIframeUrl = setInterval(function() {
try {
const iframeUrl = iframe.contentWindow.location.href;
if (iframeUrl.includes("thank-you") || iframeUrl.includes("success")) {
clearInterval(checkIframeUrl);
window.location.href = "/thank-you";
} else if (iframeUrl.includes("error") || iframeUrl.includes("denied")) {
clearInterval(checkIframeUrl);
window.location.href = "/error";
}
} catch (e) {
// Cross-origin: can't read iframe URL — expected, just keep polling
}
}, 500);
⚠️ 这种轮询方法只有在支付完成后iframe导航到同源URL时才有效。如果它在整个过程中都保持跨域,则浏览器的同源策略会阻止。
4.最佳的长期解决办法 — 请求插件支持 postMessage
由于插件开发者已经提到 postMessage,请他们把以下内容加入到他们的感谢页/错误页:
// They add this to their redirect pages:
if (window.self !== window.top) {
window.parent.postMessage(
{ action: "redirect", url: window.location.href },
"*" // or specify your domain
);
}
快速调试提示: 将
console.log("Message received:", event)作为监听器的第一行。如果它从不打印日志,说明iframe根本没有发送消息——那就是根本原因。