如何在不触发错误的情况下检测iframe是否可访问?

时间:2012-01-18 21:31:31

标签: javascript jquery security iframe exception-handling

基本上我加载了iframe,只要它触发onload事件就会从父进程访问。它工作正常,但是当iframe的内容不再在同一个域上时,我会收到错误,这是预期的。

唯一的问题是,我想抑制这些错误。不幸的是,try / catch没有捕获到这个异常并尝试访问任何这些属性以验证它们再次产生相同的错误,从而无法实现目的。

我是否有一种可靠的方法来检查iframe内容是否可以访问而不会产生任何错误消息?

由于

编辑:

为了上下文而没有人回答无关的评论;我正在编写一个小脚本,根据iframes文档的高度自动调整父页面上的iframe大小。当用户点击指向域外的iframe内的链接时,我显然无法检测到页面的高度,但我宁愿不在控制台中触发任何错误,而是优雅地处理异常。 / p>

我知道有可用的解决方法,我只是想通过弄清楚是否有一种优雅的方式来处理这类案件来教育自己,而不仅仅是采用丑陋的解决方法。

8 个答案:

答案 0 :(得分:5)

如果您可以在您希望在iframe中加载的所有网页中添加一些JavaScript,则可以使用window.postMessage,这可以免于同源政策。可能最简单的方法是让子窗口在加载时向父级发布消息,而不是使用onload。例如,您可以将其添加到每个页面:

if (window.parent) document.addEventListener( 'load', function() {
    window.parent.postMessage( "child loaded", "/" );
}, false );

只要页面加载到具有相同原点的帧中,它就会将消息发布到父窗口。然后你会这样听:

var iframe = document.getElementById( 'your-iframe' );
var origin = window.location.protocol + '://' + window.location.host;
if (window.location.port != 80) origin += ':' + window.location.port;

window.addEventListener( 'message', function (event) {
    if (event.source != iframe.contentWindow
            || event.origin != origin || event.data != "child loaded")
        return;

    // do here what you used to do on the iframe's load event
}, false );

请注意,这些示例使用W3C / Netscape事件API,因此在版本9之前无法在Internet Explorer中使用。

答案 1 :(得分:2)

试试这个:

var $frame = $("#frameId"); // swap with the id of the iframe
try {
    var canAccess = $frame.contents();
    if(!!canAccess) {
       // same domain yay you have access
       // do your thing here
    }
}
catch( e ) {
    // bummer can't do much with it
    return false;
}
编辑:添加一个try和catch,没有错误会返回false。

答案 2 :(得分:1)

jQuery approach也可以使用常规JS完成:

function iframe_accessible(theiframe) {
  var thedoc, debug=true;
  try{
    thedoc = (theiframe.contentWindow || theiframe.contentDocument);
    if (thedoc.document)
        thedoc = thedoc.document;
    if (debug)
        console.log('Accessible');
    return true;
  }
  catch(err) {
    if (debug)
        console.log("Not accessible because of\n" + err);
    return false;
  }
}

var elm = document.querySelector('iframe'); // If it exists, of course
console.log(iframe_accessible(elm));

答案 3 :(得分:0)

您可以使用iframe获取window.frames['frame_name'].contentWindow.location.href的当前网址。

如果用户已离开您的域,则无法执行此操作。遗憾...

更多信息here

答案 4 :(得分:0)

您无法从父级访问src属性吗?

据我了解,iframe元素属于“父”页面,而iframe中包含的window对象属于“子”页面。

这对我有用:

<html>
<head>
</head>
<body>
<iframe id="ifr" name="ifr" src="http://www.example.com"></iframe>
<input type="button" onclick="showSrc()" value="showSrc" />
<input type="button" onclick="showHref()" value="showHref" />
<script>
    var ifr = document.getElementById('ifr');
    function showSrc() {
        // no warning
        alert(ifr.src);
    }
    function showHref() {
        // warning
        alert(window.frames['ifr'].contentWindow.location.href);
    }

</script>
</body>
</html>

答案 5 :(得分:0)

好的,这太过分了,不过是一个黑客,也许在你的情况下不可能,但无论如何:

您可以在网站的所有页面中添加javascript包含,尝试访问开启者(父框架)并将标记(bool stillOnMySite之类的变量)设置为true。

然后

  1. 基于时间:网站页面中的脚本每秒将标志设置为true,父iframe中的脚本每秒将标志设置为false。在setTimeOut(xxx,1)中轮询iframe。如果该标志不再为真,那么用户离开了您的网站,如果该标志为真,您不应该轮询iframe,用户仍在您的网站上,您可以轮询iframe。

  2. 基于点击:使用jquery进行不显眼的javascript,您网站页面中的脚本会监控页面中所有链接中的clickevents。如果链接超出您的域,则会将父iframe中的标记设置为false。

  3. 当然,如果您无法在网页中添加脚本,那么所有理论都会崩溃。

    或者,我只是想:如果您的iframe始终在您的网站上开始,无需修改您的网站页面,只需将父iframe的n°2解决方案注入iframed页面即可。

答案 6 :(得分:0)

你能告诉我你是如何设置iframe的src的吗? 如果您使用javascript动态更改它,您的问题很容易处理。

var isXdm = false;
function setSrc(id,src){
   //detect whether src is cross domain then set the variable isXdm
   ...
}
即便如此,我认为这不是解决这个问题的好办法 希望有人能找到更好的解决方案。

答案 7 :(得分:0)

如果它的href没有指向与父页面相同的协议和主机,那么根本不渲染IFRAME(在父页面内)怎么样?我可能误解了与你拥有这两个网站有关的事情,或者只有其中一个(以及哪一个)。但是,如果您拥有父页面站点,您应该能够执行此操作,无论是在服务器上(甚至包括IFRAME之前),还是在客户端上的某个时刻(页面加载/ doc-load)。