sua*_*kim 10 javascript iframe messaging cross-domain
我有一个在"外国"页面(不同的域等)上的iframe内运行的应用程序.为了允许iframe和父进程之间的一些基本通信,我在父页面上加载了我的一些脚本并postMessage用来做一些跨文档消息传递.
大多数情况下,此通信按预期工作,但有时我会看到一些错误报告给我的错误跟踪工具,无法弄清楚它们发生的原因.
这是一些示例代码:
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);
// ...
Run Code Online (Sandbox Code Playgroud)
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' }, '*');
// ...
Run Code Online (Sandbox Code Playgroud)
当超时命中并报告错误时,会发生什么?
我的更多信息和想法:
问题似乎出在您发送响应的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,并且它们可以很好地通信。
父级.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>Run Code Online (Sandbox Code Playgroud)
孩子.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>Run Code Online (Sandbox Code Playgroud)
希望有帮助!