在IFrame&父母 [英] Issues with Cross Document Messaging between IFrame & Parent

查看:171
本文介绍了在IFrame&父母的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个在外部页面(不同的域等)上的iframe中运行的应用程序。为了允许在iframe&父级,我在父页面上加载一些脚本,并使用 postMessage 执行一些跨文档消息传递。



大多数时候,这种沟通的工作原理,但有时我看到一些错误报告我的错误跟踪工具,不能弄清楚为什么他们发生。



这里有一些示例代码:



PluginOnParent.js

  // ... 
window.addEventListener('message',function(e){
//检查邮件来源等...
if .data.type ==='iFrameRequest'){
e.source.postMessage({
type:'parentResponse',
responseData:someInterestingData
},e.origin) ;
}
// ...
},false);
// ...

AppInsideIFrame.js

  // ... 
var timeoutId;


try {
if(window.self === window.top){
//我们不在IFrame里面,不要做任何事情...
return;
}
} catch(e){
//由于同源策略,浏览器可以阻止对window.top的访问。
//参见http://stackoverflow.com/a/326076
//如果发生这种情况,我们在一个IFrame ...
}

函数messageHandler(e){
if(e.data&&(e.data.type ==='parentResponse')){
window.clearTimeout(timeoutId);
window.removeEventListener('message',messageHandler);
//对发送的数据做一些事情
}
}

timeoutId = window.setTimeout(function(){
errorTracking.report('与父页面通信失败');
window.removeEventListener('message',messageHandler);
},500);

window.addEventListener('message',messageHandler,false);
window.parent.postMessage({type:'iFrameRequest'},'*');
// ...

这里会发生什么,当超时命中,报告?



更多信息&




  • 我无法控制父页面。

  • 它似乎不是一个一般的配置问题(CORS等),因为错误发生在大部分时间工作的同一页上。

  • 我们不支持IE <

  • 我的错误报告工具会报告大量不同的浏览器,其中包括最新版本的浏览器(FF 49, Chrome 43在Android 5,Chrome 53在Win和Android 6,移动Safari 10,...)


    • 因此,它似乎不是一个问题与特定浏览器或版本相关。


  • 超时500 ms只是我选择的一个魔法数字,我认为这是完全安全的。 ..


解决方案

问题似乎在您的 PluginOnParent.js ,您正在发送您的回复。而不是使用e.origin(在开发者工具检查后返回null) - 尝试使用文字'*',因为它在 postMessage 用法在 targetOrigin 的说明中):



https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage



此外,作为奖励,我只是测试这两个不同的域,它的工作原理。我将Parent.html放在一个域Web服务器上,并将iframe的src更改为完全不同的域上的child.html,并且他们一起通信很好。



strong>



 < html>< head> < script type =text / javascript>函数parentInitialize(){window.addEventListener('message',function(e){//检查消息来源等... if(e.data.type ==='iFrameRequest'){var obj = {type:'parentResponse ',responseData:'some response'}; e.source.postMessage(obj,'*');} // ...})}< / script>< / head>< body style =颜色:rgb(72,222,218); onload =javascript:parentInitialize();> < iframe src =child.htmlstyle =width:500px; height:350px;>< / iframe>< / body>< / html>  


b

 < html>< head> < script type =text / javascript> function childInitialize(){// ... var timeoutId; try {if(window.self === window.top){//我们不是一个IFrame,不要做任何事情... return; }} catch(e){//由于同源策略,浏览器可以阻止对window.top的访问。 //参见http://stackoverflow.com/a/326076 //如果发生这种情况,我们在一个IFrame ...} function messageHandler(e){if(e.data&&(e.data.type) ==='parentResponse')){window.clearTimeout(timeoutId); window.removeEventListener('message',messageHandler); //做一些与发送数据的东西var obj = document.getElementById(status); obj.value = e.data.responseData; }} timeoutId = window.setTimeout(function(){var obj = document.getElementById(status); obj.value ='与父页面通信失败'; window.removeEventListener('message',messageHandler);},500 ); window.addEventListener('message',messageHandler,false); window.parent.postMessage({type:'iFrameRequest}},'*'); // ...}< / script>< / head>< body style =background-color:rgb(0,148,255) onload =javascript:childInitialize();> < textarea type =textstyle =width:400px; height:250px; id =status/>< / body>< / html>  



希望有所帮助!


I have an application running inside an iframe on a "foreign" page (different domain etc.). To allow some basic communication between the iframe & the parent, I load some script of mine on the parent page and use postMessage to do some cross document messaging.

Most of the time this communication works as intended, but sometimes I see some errors reported to my error tracking tool and can't figure out why they happen.

Here's some exemplary code:

PluginOnParent.js

// ...
window.addEventListener('message', function(e) {
    // Check message origin etc...
    if (e.data.type === 'iFrameRequest') {
        e.source.postMessage({
            type: 'parentResponse',
            responseData: someInterestingData
        }, e.origin);
    }
    // ...
}, false);
// ...

AppInsideIFrame.js

// ...
var timeoutId;


try {
    if (window.self === window.top) {
        // We're not inside an IFrame, don't do anything...
        return;
    }
} catch (e) {
    // Browsers can block access to window.top due to same origin policy.
    // See http://stackoverflow.com/a/326076
    // If this happens, we are inside an IFrame...
}

function messageHandler(e) {
    if (e.data && (e.data.type === 'parentResponse')) {
        window.clearTimeout(timeoutId);
        window.removeEventListener('message', messageHandler);
        // Do some stuff with the sent data
    }
}

timeoutId = window.setTimeout(function() {
    errorTracking.report('Communication with parent page failed');
    window.removeEventListener('message', messageHandler);
}, 500);

window.addEventListener('message', messageHandler, false);
window.parent.postMessage({ type: 'iFrameRequest' }, '*');
// ...

What happens here, when the timeout hits and the error is reported?

Some more info & thoughts of mine:

  • I have no control over the parent page myself
  • It doesn't seem to be a general "configuration" issue (CORS etc.) since the error happens on the same page where it works most of the time
  • We don't support IE < 10 and other "legacy" browser versions at all, so those are no issue here
  • My error reporting tool reports a multitude of different browsers amongst which are the latest versions of them (FF 49, Chrome 43 on Android 5, Chrome 53 on Win and Android 6, Mobile Safari 10, ...)
    • Therefore it doesn't seem like it's an issue related to specific browsers or versions.
  • The timeout of 500 ms is just some magic number I chose which I thought would be completely safe...

解决方案

The problem appears to be in your PluginOnParent.js, where you are sending your response. Instead of using "e.origin" (which upon inspection in the developer tools was returning "null") -- try using the literal '*', as it states in the following documentation on postMessage usage (in the description for targetOrigin):

https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage

Also, as a bonus, I just tested this across two different domains and it works as well. I placed Parent.html on one domains web server, and changed the iframe's src to be child.html on a completely different domain, and they communicated together just fine.

Parent.html

<html>
<head>
    <script type="text/javascript">
        function parentInitialize() {
            window.addEventListener('message', function (e) {
                // Check message origin etc...
                if (e.data.type === 'iFrameRequest') {
                    var obj = {
                        type: 'parentResponse',
                        responseData: 'some response'
                    };
                    e.source.postMessage(obj, '*');
                }
                // ...
            })
		}
    </script>
</head>
<body style="background-color: rgb(72, 222, 218);" onload="javascript: parentInitialize();">
    <iframe src="child.html" style="width: 500px; height:350px;"></iframe>
</body>
</html>

Child.html

<html>
<head>
    <script type="text/javascript">
        function childInitialize() {
            // ...
            var timeoutId;


            try {
                if (window.self === window.top) {
                    // We're not inside an IFrame, don't do anything...
                    return;
                }
            } catch (e) {
                // Browsers can block access to window.top due to same origin policy.
                // See http://stackoverflow.com/a/326076
                // If this happens, we are inside an IFrame...
            }

            function messageHandler(e) {
                if (e.data && (e.data.type === 'parentResponse')) {
                    window.clearTimeout(timeoutId);
                    window.removeEventListener('message', messageHandler);
                    // Do some stuff with the sent data
                    var obj = document.getElementById("status");
                    obj.value = e.data.responseData;
                }
            }

            timeoutId = window.setTimeout(function () {
                var obj = document.getElementById("status");
                obj.value = 'Communication with parent page failed';
                window.removeEventListener('message', messageHandler);
            }, 500);

            window.addEventListener('message', messageHandler, false);
            window.parent.postMessage({ type: 'iFrameRequest' }, '*');
            // ...
        }
    </script>
</head>
<body style="background-color: rgb(0, 148, 255);" onload="javascript: childInitialize();">
    <textarea type="text" style="width:400px; height:250px;" id="status" />
</body>
</html>

Hope that helps!

这篇关于在IFrame&amp;父母的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆