【问题标题】:How to detect if an iframe is accessible without triggering an error?如何在不触发错误的情况下检测 iframe 是否可访问?
【发布时间】:2012-02-13 14:55:58
【问题描述】:

基本上,我加载了一个 iframe,只要它触发 onload 事件,就会从父级访问它。它工作正常,但是当 iframe 的内容不再在同一个域上时出现错误,这是意料之中的。

唯一的问题是,我想抑制这些错误。不幸的是,try/catch 没有捕捉到这个异常,并且试图访问这些属性中的任何一个来验证它们都会再次产生相同的错误,从而违背了目的。

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

谢谢

编辑:

为了上下文,不要让人们用不相关的 cmets 回答;我正在编写一个小脚本,它会根据 iframe 文档的高度自动调整父页面上的 iframe 大小。当用户单击指向域外的 iframe 内的链接时,我显然无法检测到页面的高度,但我不希望在控制台中触发任何错误,而是优雅地处理异常。

我知道有可用的变通方法,我只是想通过了解是否有一种优雅的方法来处理这些情况,而不是仅仅诉诸丑陋的变通方法来教育自己。

【问题讨论】:

  • 也许这是一个告诉你不要使用 iframe 的标志...
  • 认真的吗?如果您没有什么可贡献的,请不要发表评论。
  • Naatan,这家伙给你的建议是我 +1。如果它们的协议和主机名与字母不匹配,则您不能让页面和框架相互通信或操纵彼此的内容(根本;甚至不阅读)。就是这样,永远不会有办法让它表现得不同。这是为了防止恶意的家伙与无辜的人混在一起并从那里偷窃。
  • Hari,我很清楚这一点,但鉴于我没有给你我的问题的背景,你不应该编造一个。在您的情况下,我的问题毫无意义,我同意。但这无关紧要,我在问一个问题,而您所做的只是说“好吧,在我的情况下,您的问题没有任何意义,所以您不应该做您想做的事情”。这无关紧要。不过,我将根据上下文更新我的主要问题,以免继续使用这些类型的 cmets。
  • 虽然这个答案与这个问题无关,但提醒所有开发人员“尽可能避免使用 iframe”是一个可靠的建议。 :(

标签: javascript jquery security iframe exception-handling


【解决方案1】:

如果您可以在域中的所有页面中添加一些 JavaScript,并希望在 iframe 中加载,则可以使用 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,因此无法在 Internet Explorer 9 之前的版本中运行。

【讨论】:

    【解决方案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 and catch,没有错误将返回false。

    【讨论】:

    • 在任何一种情况下(可访问或不可访问的 iframe)都会触发相同的 IF 语句。奇怪的是没有安全错误,我想知道你是否在这里..
    • 这对我来说很好用。内部域的触发器,外部域的忽略。没有错误。
    【解决方案3】:

    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));

    【讨论】:

      【解决方案4】:

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

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

      更多信息here

      【讨论】:

      • 感谢您的回复。我知道我可以做到,但这不是我的问题。问题是,当 iframe 在父域之外提供内容时,如果浏览器不向我抛出权限错误,我什至无法“尝试”获取此信息。我想抑制这些错误,基本上就像使用 try/catch 短语一样,只是出于某种神奇的原因,这些类型的错误不会被 try/catch 捕获(至少在 Firefox 中不会)。
      • 我认为没有办法抑制此类浏览器错误。 404 AJAX 请求也是如此。
      • @Naatan:最坏的情况,您可以在 0 毫秒内安排 setTimeout 来解决这个问题。
      • @Naatan:不会,但是如果你在它出错之前安排另一个,你可以继续运行。
      【解决方案5】:

      您不能从父级访问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>
      

      【讨论】:

      • 我可以,但问题是可以点击 iframe 内的链接,这不会改变父级的 src 属性。
      • @Naatan 该死。这是正确的。那么我认为无论如何都不会出现错误。
      【解决方案6】:

      好吧,这有点矫枉过正,不过是一种技巧,在你的情况下可能是不可能的,但无论如何:

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

      然后

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

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

      当然,如果您不能在您的网站页面中添加脚本,那么所有这些理论都会崩溃。

      另外,我只是想:如果您的 iframe 始终在您的网站上启动,则无需修改您的网站页面,只需将 n°2 解决方案从父 iframe 注入 iframed 页面。

      【讨论】:

      • 有趣的方法,虽然我希望开发没有依赖关系的脚本。
      • 使用替代方案,即如果您的 iframe 始终在您的网站上启动,您可以在 iframe 父级 iframe 页面的每个链接上注入 onclick 监视器。 jQuery 让它变得非常简单,但你也可以用纯 javascript 来完成。祝你好运!
      【解决方案7】:

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

      var isXdm = false;
      function setSrc(id,src){
         //detect whether src is cross domain then set the variable isXdm
         ...
      }
      

      即便如此,我认为这不是解决这个问题的好方法。
      希望有人能找到更好的解决方案。

      【讨论】:

      • 嗨西蒙,问题不在于 src 属性,我意识到我可以轻松阅读此内容。这是关于 iframe 在加载后更改位置(例如,当用户单击加载页面中的链接时)。
      【解决方案8】:

      如果 IFRAME 的 href 没有指向与父页面相同的协议和主机,那么根本不渲染 IFRAME 怎么样?我可能会误解与您是否拥有这两个网站或仅拥有其中一个(以及哪一个)有关的事情。但是,如果您拥有父页面站点,您应该能够做到这一点,无论是在服务器上(甚至包括 IFRAME 之前),还是在客户端的某个时间点(页面加载/文档加载)。

      【讨论】:

      • 嘿,哈里,我遇到的问题不是加载了原始 src,而是人们点击了加载的 iframe 中指向域外的链接。不过,我想我将不得不求助于解决方法。
      • 嗯,点击 IFRAME 中的链接不应导致此类行为;它的工作方式应该与您在顶部窗口中打开该框架页面的方式相同。您要么尝试与该 IFRAME 对话(或操作其内容),要么 IFRAME 具有引用顶部窗口的代码。我开始感觉到你问题中的秘密......
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-22
      相关资源
      最近更新 更多