检查 JS 是否有权访问 iframe 的文档

Check if JS has access to an iframe's document

提问人:Fabrício Matté 提问时间:8/9/2012 最后编辑:CommunityFabrício Matté 更新时间:1/27/2020 访问量:6593

问:

是否有任何标准方法可以知道我的脚本是否有权访问 的文档?iframe

我在网上找不到任何东西,所以我想出了这个:

function checkifr() {
    function errHandler() {
        alert('Error. Try again later.');
    }
    var ifr = $('#ifr')[0]; //the iframe DOM element

    try {
        var d = ifr.contentWindow || ifr.contentDocument;
        if (!d) {
            errHandler();
            return false;
        }

        var b = $('#ifr').contents().find('body');
        //... manipulate iframe content

    } catch(e) {
        errHandler();
    }
}

它有效,当我尝试访问的内容时,Firefox会抛出错误并最终进入块中。Chrome 在控制台中显示警告,但从未进入阻止,它似乎会返回这些尝试,因此初始会处理它。Opera 和 IE 的行为类似于 FF。 编辑:使用上面的代码,现在 Chrome 返回一个“空”的 Window 对象(没有属性),它不会触发我的阻止。查看 Esailija 的答案,该答案在跨浏览器中效果很好!iframecatchUnsafe JavaScript attempt to access framecatchnullif (!d)if

这是小提琴

我无法测试 .iframesrcwindow.location

理由背景:这是因为这个函数是我正在开发的一个小型图像上传插件的一部分(使用 IE<9 作为目标,因为 IE9 不支持 XHR2),目标主要是验证连接错误/超时/等。这些错误的默认浏览器页面受同源策略的约束,因此本问题的目的。我不想发送 ajax 调用来检查页面是否可用,因为我想验证提交请求本身。jQuery 的 .load 处理程序不会因错误而触发,jQuery 的 .error 和 HTML 属性不适用于此。此处提供了工作脚本的插图,但您可以完全忽略它,只需回答以下问题。iframeonerror

请注意,上面的块只是为了说明为什么我不能使用 .iframe.src

我确实认为应该有一种更简单/标准的方法来检查“可访问性”,但我在网络上也找不到任何东西,除了只是检查并且不适用于许多情况的半解决方案之外,我找不到任何东西。如果我的 hackish / block 被认为是技术上“干净”的解决方案,如果没有找到更好的选择,其他人可能会重新使用它。iframeiframe.srctrycatch

那么,是否有任何标准或更简单的方法或jQuery插件来检查我的脚本是否有权访问文档,而无需将文档与文档进行比较?如果可能,控制台中没有 / 阻止和错误/警告。iframeiframesrcwindow.locationtrycatch

JavaScript jQuery iframe 同源策略

评论

0赞 Šime Vidas 8/9/2012
.documentWindow?哪个浏览器实现了这一点?
0赞 Esailija 8/9/2012
哦,是的,应该是.contentWindow
0赞 Fabrício Matté 8/9/2012
很确定我从 SO 中的另一个答案中获取了这部分,但不错的发现! 在我测试过的所有浏览器中都返回 undefined。.我会寻找答案来检查这是否是错别字。documentWindow
0赞 Fabrício Matté 8/9/2012
是的,这是我的一个错别字,感谢 @ŠimeVidas 和 Esa!

答:

1赞 jfriend00 8/9/2012 #1

这里有一个想法,无论访问是否引发异常,它都会起作用:

function checkFrameAccess(ifr) {
    try {
        var doc = ifr.contentDocument || ifr.contentWindow.document;
        var origClass = doc.body.className;
        var newClass = origClass += " xxxxx";
        doc.body.className = newClass;
        var valid = doc.body.className == newClass;
        doc.body.className = origClass;
        return(valid);
    } catch(e) {
        return(false);
    }
}

如果它们抛出异常,则最终进入异常处理程序并返回 .如果它们没有抛出异常,那么您可以测试是否可以实际修改帧中 body 标签的 className。如果修改有效,那么显然,您可以对其进行修改。如果没有,那么它不会让您访问它。false

评论

1赞 Fabrício Matté 8/9/2012
-1 jQuery 不够。说真的,你的答案是干净易懂的。+1 用于在 Esailija 之前回答。
12赞 Esailija 8/9/2012 #2

这是另一种选择,如果不尝试捕捉,就无法真正做到这一点。

测试 http://jsfiddle.net/LHjwZ/11/

function checkIframe( ifr ) {
    var key = ( +new Date ) + "" + Math.random();

    try {
        var global = ifr.contentWindow;
        global[key] = "asd";
        return global[key] === "asd";
    }
    catch( e ) {
        return false;
    }
}

评论

0赞 Fabrício Matté 8/9/2012
我明白了,尝试在 iframe 中设置 var 看起来比我的代码更干净,并且很容易添加到抽象级别。+1,秒,而我阅读其他答案并测试它们。contentWindow=]
0赞 Esailija 8/9/2012
@FabrícioMatté也是多余的,因为它会抛出一个错误,如果它是或ifglobal[key]nullundefined
0赞 Fabrício Matté 8/9/2012
是的,设置一个以 miliseconds 时间戳命名的窗口属性似乎有点矫枉过正,但毫无疑问,这是代码 pr0ness 的标志!Math.random()