如何创建与 postMessage 配合使用的动态 iframe
How to create dynamic iframe that works with postMessage
我正在开展一个项目,我们的 Web 应用程序需要通过 postMessage 协议与第三方应用程序集成。出于说明目的,假设这是代码,它工作得很好:
<html>
<head>
<script>
var ovsDomain = '3rd.party.vendor',
ovsOrigin = 'https://' + ovsDomain,
ovsApiUrl = ovsHost + '/webapi.html';
function begin() {
var ovsFrame = document.getElementById( 'ovs' );
if ( window.postMessage ) {
if ( window.addEventListener ) {
window.addEventListener( 'message', onMessage );
} else {
window.attachEvent( 'onmessage', onMessage );
}
}
ovsFrame.src = ovsApiUrl + '#' + encodeURIComponent( document.location.href );
ovsFrame.contentWindow.postMessage( JSON.stringify( {
cmd: 'initialize',
session: 'test_session'
} ), ovsOrigin );
}
function post() {
var ovsFrame = document.getElementById( 'ovs' ),
msg = JSON.stringify( {
cmd: 'send',
data: 'test data'
} );
ovsFrame.contentWindow.postMessage( msg, ovsHost );
}
function end() {
var ovsFrame = document.getElementById( 'ovs' );
ovsFrame.contentWindow.postMessage( JSON.stringify( {
cmd: 'close'
} ), ovsOrigin );
}
function onMessage( evt ) {
var data,
ovsFrame = document.getElementById( 'ovs' );
if ( evt.origin === ovsHost && ovsFrame.contentWindow === evt.source ) {
try {
data = JSON.parse(evt.data);
} catch ( e ) {
alert( 'bad data' );
}
switch ( data.msg ) {
case 'close':
alert( 'closed' );
break;
case 'initialized':
alert( 'initialized' );
break;
}
}
}
</script>
</head>
<body>
<input type='button' value='Begin' onclick='begin()' />
<input type='button' value='Post' onclick='post()' />
<input type='button' value='End' onclick='end()' />
<iframe id='ovs' sandbox='allow-scripts allow-same-origin allow-popups' src='https://3rd.party.vendor/webapi.html' style='display:none'></iframe>
</body>
</html>
我想有条件地 create/load iframe 元素基于 a) 是否启用该功能和 b) 无论 URL 应该用于特定客户端 and/or 供应商 API 我们使用的是。因此,我尝试从 HTML 文档中删除静态 iframe,并将以下调整添加到我的 begin 函数中:
function begin() {
var ovsFrame = document.createElement( 'iframe' );
if ( window.postMessage ) {
if ( window.addEventListener ) {
window.addEventListener( 'message', onMessage );
ovsFrame.addEventListener( 'load', onFrameLoad );
} else {
window.attachEvent( 'onmessage', onMessage );
ovsFrame.attachEvent( 'load', onFrameLoad );
}
}
ovsFrame.id = 'crs';
ovsFrame.src = ovsOrigin;
document.body.appendChild( ovsFrame );
}
function onFrameLoad() {
var ovsFrame = document.getElementById( 'ovs' );
ovsFrame.src = ovsApiUrl + '#' + encodeURIComponent( document.location.href );
ovsFrame.contentWindow.postMessage( JSON.stringify( {
cmd: 'initialize',
session: 'test_session'
} ), ovsOrigin );
}
iframe 已创建并添加到 DOM。初始 URL 已加载,但 API 想要创建的弹出窗口被阻止。更重要的是,我发送消息的尝试被阻止了:
无法在 'DOMWindow' 上执行 'postMessage':提供的目标来源 ('https://3rd.party.vendor') does not match the recipient window's origin ('https://althost.meditech.com:4433')。
我的理解是因为我在我的文档中创建了 iframe,它继承了我的文档的域。一旦完成,我就不能强制将其设置为 OV 的域,例如
ovsFrame.contentWindow.document.domain = ovsDomain;
由于OV域名与我无关
对于我能找到的所有文档,没有任何地方明确说明你不能这样做(创建动态元素),尽管我没有找到一个例子,其中有人在 HTML 所以它开始感觉像是我不知道的那些肮脏的小秘密(或传统智慧花絮)之一。
任何建议将不胜感激,即使它确认无法完成。
我已通读同源政策文档和
我已经确定了解决此问题的方法,以防其他人遇到此问题并需要解决方案。动态创建 iframe 元素将继承脚本页面的来源;因为这是我的页面,所以我可以加载我托管的 HTML 文档,这将静态加载第 3 方 iframe。一旦我有了这个新页面,我就可以使用 window.postMessage 通过新页面与第 3 方页面进行通信,实际上是通过我的可信来源代理通信。感觉有点笨重,但看起来很不错,也很管用。
我正在开展一个项目,我们的 Web 应用程序需要通过 postMessage 协议与第三方应用程序集成。出于说明目的,假设这是代码,它工作得很好:
<html>
<head>
<script>
var ovsDomain = '3rd.party.vendor',
ovsOrigin = 'https://' + ovsDomain,
ovsApiUrl = ovsHost + '/webapi.html';
function begin() {
var ovsFrame = document.getElementById( 'ovs' );
if ( window.postMessage ) {
if ( window.addEventListener ) {
window.addEventListener( 'message', onMessage );
} else {
window.attachEvent( 'onmessage', onMessage );
}
}
ovsFrame.src = ovsApiUrl + '#' + encodeURIComponent( document.location.href );
ovsFrame.contentWindow.postMessage( JSON.stringify( {
cmd: 'initialize',
session: 'test_session'
} ), ovsOrigin );
}
function post() {
var ovsFrame = document.getElementById( 'ovs' ),
msg = JSON.stringify( {
cmd: 'send',
data: 'test data'
} );
ovsFrame.contentWindow.postMessage( msg, ovsHost );
}
function end() {
var ovsFrame = document.getElementById( 'ovs' );
ovsFrame.contentWindow.postMessage( JSON.stringify( {
cmd: 'close'
} ), ovsOrigin );
}
function onMessage( evt ) {
var data,
ovsFrame = document.getElementById( 'ovs' );
if ( evt.origin === ovsHost && ovsFrame.contentWindow === evt.source ) {
try {
data = JSON.parse(evt.data);
} catch ( e ) {
alert( 'bad data' );
}
switch ( data.msg ) {
case 'close':
alert( 'closed' );
break;
case 'initialized':
alert( 'initialized' );
break;
}
}
}
</script>
</head>
<body>
<input type='button' value='Begin' onclick='begin()' />
<input type='button' value='Post' onclick='post()' />
<input type='button' value='End' onclick='end()' />
<iframe id='ovs' sandbox='allow-scripts allow-same-origin allow-popups' src='https://3rd.party.vendor/webapi.html' style='display:none'></iframe>
</body>
</html>
我想有条件地 create/load iframe 元素基于 a) 是否启用该功能和 b) 无论 URL 应该用于特定客户端 and/or 供应商 API 我们使用的是。因此,我尝试从 HTML 文档中删除静态 iframe,并将以下调整添加到我的 begin 函数中:
function begin() {
var ovsFrame = document.createElement( 'iframe' );
if ( window.postMessage ) {
if ( window.addEventListener ) {
window.addEventListener( 'message', onMessage );
ovsFrame.addEventListener( 'load', onFrameLoad );
} else {
window.attachEvent( 'onmessage', onMessage );
ovsFrame.attachEvent( 'load', onFrameLoad );
}
}
ovsFrame.id = 'crs';
ovsFrame.src = ovsOrigin;
document.body.appendChild( ovsFrame );
}
function onFrameLoad() {
var ovsFrame = document.getElementById( 'ovs' );
ovsFrame.src = ovsApiUrl + '#' + encodeURIComponent( document.location.href );
ovsFrame.contentWindow.postMessage( JSON.stringify( {
cmd: 'initialize',
session: 'test_session'
} ), ovsOrigin );
}
iframe 已创建并添加到 DOM。初始 URL 已加载,但 API 想要创建的弹出窗口被阻止。更重要的是,我发送消息的尝试被阻止了:
无法在 'DOMWindow' 上执行 'postMessage':提供的目标来源 ('https://3rd.party.vendor') does not match the recipient window's origin ('https://althost.meditech.com:4433')。
我的理解是因为我在我的文档中创建了 iframe,它继承了我的文档的域。一旦完成,我就不能强制将其设置为 OV 的域,例如
ovsFrame.contentWindow.document.domain = ovsDomain;
由于OV域名与我无关
对于我能找到的所有文档,没有任何地方明确说明你不能这样做(创建动态元素),尽管我没有找到一个例子,其中有人在 HTML 所以它开始感觉像是我不知道的那些肮脏的小秘密(或传统智慧花絮)之一。
任何建议将不胜感激,即使它确认无法完成。 我已通读同源政策文档和
我已经确定了解决此问题的方法,以防其他人遇到此问题并需要解决方案。动态创建 iframe 元素将继承脚本页面的来源;因为这是我的页面,所以我可以加载我托管的 HTML 文档,这将静态加载第 3 方 iframe。一旦我有了这个新页面,我就可以使用 window.postMessage 通过新页面与第 3 方页面进行通信,实际上是通过我的可信来源代理通信。感觉有点笨重,但看起来很不错,也很管用。