如何通过postMessage执行一个函数

Ale*_*lex 10 javascript jquery postmessage

我在iframe中有这个代码:

window.addEventListener('message', function(e){

  if(e.data == 'test')
    console.log(e);

}, false);
Run Code Online (Sandbox Code Playgroud)

这在父文档中:

$('#the_iframe').get(0).contentWindow.postMessage('test', 'http://localhost/');
Run Code Online (Sandbox Code Playgroud)

因此父文档向iframe发送"测试"消息并且它可以正常工作.

但是如何在父文档中定义一个函数,并以某种方式通过postMessage将此函数发送到iframe,iframe将在本地执行该函数?

该函数对文档进行了一些更改,如下所示:

var func = function(){
  $("#some_div").addClass('sss');
}
Run Code Online (Sandbox Code Playgroud)

(#some_div存在于iframe中,而不是父文档中)

o.v*_*.v. 14

没有什么可以阻止您将字符串化的函数作为postmessage事件数据传递.对于任何函数声明,实现都是微不足道的

function doSomething(){
    alert("hello world!");
}
Run Code Online (Sandbox Code Playgroud)

你可以用encodeURI它的字符串解释:

console.log(encodeURI(doSomething.toString()));
//function%20doSomething()%20%7B%0A%20%20%20%20alert(%22hello%20world!%22);%0A%7D
Run Code Online (Sandbox Code Playgroud)

然后它可以作为闭包的一部分执行 - 这不像是过于富有想象力

eval('('+decodeURI(strCallback)+')();');
Run Code Online (Sandbox Code Playgroud)

没有跨框架架构的情况下,有一个小提琴的概念证明 - 我会看看我是否可以组合一个postMessage版本,但是主持w/jsfiddle是非常重要的

更新

正如所承诺的那样,一个完整的模型可以工作(链接如下).通过正确的event.origin检查,这将是足够难以穿透的,但我知道我们的安全团队永远不会eval像这样生产:)

鉴于该选项,我建议在两个页面中对功能进行规范化,以便只需要传递参数消息(即传递参数而不是函数); 但是肯定有一些场景,这是一种首选的方法.

家长代码:

document.domain = "fiddle.jshell.net";//sync the domains
window.addEventListener("message", receiveMessage, false);//set up the listener

function receiveMessage(e) {
    try {
        //attempt to deserialize function and execute as closure
        eval('(' + decodeURI(e.data) + ')();');
    } catch(e) {}
}
Run Code Online (Sandbox Code Playgroud)

iframe代码:

document.domain = "fiddle.jshell.net";//sync the domains
window.addEventListener("message", receiveMessage, false);//set up the listener

function receiveMessage(e) {
    //"reply" with a serialized function
    e.source.postMessage(serializeFunction(doSomething), "http://fiddle.jshell.net");
}

function serializeFunction(f) {
    return encodeURI(f.toString());
}

function doSomething() {
    alert("hello world!");
}
Run Code Online (Sandbox Code Playgroud)

原型模型:父代码iframe代码.

  • @Alex:是的,它适用于您定义的任何**函数 - 或者更确切地说,任何函数都不是用本机代码编写的(即,您无法看到`window.alert的源代码的字符串表示形式) `) (2认同)
  • 只需记住,您最终会获得最差的实践代码(evals,在全局上下文中执行的函数等) (2认同)

Ber*_*rgi 10

你不能真的.虽然postMessage(草案)规范讨论了结构化对象,例如嵌套对象和数组,JavaScript值(字符串,数字,日期等)和某些数据对象,例如File Blob,FileList和ArrayBuffer对象大多数浏览器只允许字符串(当然包括JSON).在MDNdev.opera上阅读更多内容.但我很确定发送函数对象是不可能的,至少不能作为保留其范围的闭包.

所以,你在字符串化的功能,并结束eval()它在iframe中,如果你真的想从父窗口执行一些代码.但是,我认为任何申请都没有理由允许评估任意代码(即使是来自注册域名); 最好是构建一个消息API,它可以接收(JSON-)字符串命令并调用自己的方法.