如何创建适用于postMessage

时间:2016-07-26 20:23:43

标签: javascript html5 iframe postmessage

我正在开展一个项目,我们的网络应用需要通过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>

我想根据以下内容有条件地创建/加载iframe元素:a)是否启用了该功能; b)我们正在使用的特定客户端和/或供应商API的URL应该是什么。所以我尝试从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想要创建的弹出窗口。更重要的是,我对postMessage的尝试被阻止了:

无法执行&#39; postMessage&#39;在&#39; DOMWindow&#39;:提供的目标来源(&#39; https://3rd.party.vendor&#39;)与收件人窗口的来源不匹配(&#39; https://althost.meditech.com:4433 &#39)

我的理解是因为我在文档中创建了iframe,它继承了我的文档域。一旦完成,我就无法将其强制设置到OV域,例如

ovsFrame.contentWindow.document.domain = ovsDomain;

由于OV域与我的无关。

对于我能找到的所有文档,没有明确说明你不能这样做(创建一个动态元素)虽然我找不到一个例子,其中有人在HTML中没有静态iframe元素所以它开始感觉像是我不知情的那些肮脏的小秘密(或传统的智慧花絮)之一。

任何建议都会受到赞赏,即使它确认无法完成。 我已阅读同源政策文档和

1 个答案:

答案 0 :(得分:1)

我已经确定了解决此问题的方法,以防其他人体验并需要解决方案。动态创建iframe元素将继承脚本页面的原点;因为它是我的页面,我可以加载我正在托管的HTML文档,这将静态加载第三方iframe。一旦我在混合中有了这个新页面,我就可以使用window.postMessage通过新页面与第三方页面进行通信,实际上是通过我信任的来源代理通信。它感觉有点笨重,但似乎听起来很有效。