web-dev-qa-db-ja.com

プログラムで作成された<iframe>のドキュメントオブジェクトにアクセスしようとすると、「アクセスが拒否されました」JavaScriptエラー(IEのみ)

JavaScriptを使用して<iframe>要素を作成し、DOMに追加する必要があるプロジェクトがあります。その後、<iframe>にコンテンツを挿入する必要があります。これは、サードパーティのWebサイトに埋め込まれるウィジェットです。

ページをロードしたくないので、<iframe>の「src」属性を設定しません。むしろ、CSSまたはJavaScriptが親ページと競合しないように、挿入するコンテンツを分離/サンドボックス化するために使用されます。 JSONPを使用して、サーバーからHTMLコンテンツをロードし、この<iframe>に挿入しています。

1つの重大な例外を除いて、これは正常に機能します-document.domainプロパティが親ページ(このウィジェットがデプロイされている特定の環境にある可能性があります)、Internet Explorer(おそらくすべてのバージョンですが、 6、7、および8)で確認)は、作成したこの<iframe>のドキュメントオブジェクトにアクセスしようとすると、「アクセスが拒否されました」というエラーが表示されます。私がテストした他のブラウザー(すべての主要な最新のブラウザー)では発生しません。

Internet Explorerでは、相互に通信するすべてのウィンドウ/フレームのdocument.domainを同じ値に設定する必要があることを認識しているため、これはある程度理にかなっています。ただし、アクセスできないドキュメントにこの値を設定する方法を知りません。

誰かがこれを行う方法を知っていますか?この動的に作成された<iframe>のdocument.domainプロパティを何らかの方法で設定しますか?または、私はそれを正しい角度から見ていませんか?この問題にぶつかることなく、私が目指していることを達成する別の方法はありますか?隔離/サンドボックス化されたウィンドウはこのウィジェットの機能にとって重要であるため、どの場合でも<iframe>を使用する必要があります。

これが私のテストコードです。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>Document.domain Test</title>
    <script type="text/javascript">
      document.domain = 'onespot.com'; // set the page's document.domain
    </script>
  </head>
  <body>
    <p>This is a paragraph above the &lt;iframe&gt;.</p>
    <div id="placeholder"></div>
    <p>This is a paragraph below the &lt;iframe&gt;.</p>
    <script type="text/javascript">
      var iframe = document.createElement('iframe'), doc; // create <iframe> element
      document.getElementById('placeholder').appendChild(iframe); // append <iframe> element to the placeholder element
      setTimeout(function() { // set a timeout to give browsers a chance to recognize the <iframe>
        doc = iframe.contentWindow || iframe.contentDocument; // get a handle on the <iframe> document
        alert(doc);
        if (doc.document) { // HEREIN LIES THE PROBLEM
          doc = doc.document;
        }
        doc.body.innerHTML = '<h1>Hello!</h1>'; // add an element
      }, 10);
    </script>
  </body>
</html>

私はそれをホストしました:

http://troy.onespot.com/static/access_denied.html

IEでこのページを読み込むとわかるように、alert()を呼び出す時点で、<iframe>のウィンドウオブジェクトにハンドルがあります。ドキュメントオブジェクトに深く入り込むことはできません。

ヘルプや提案をありがとう!私はこれに対する解決策を見つけるのを手伝ってくれる人には誰でもお世話になります。

79
Bungle

document.domainプロパティが親ページで設定されている場合、Internet Explorerから「アクセスが拒否されました」というメッセージが表示されます

はぁ。ええ、それはIEの問題です(この種の不愉快さについて文書化された標準がないので、言うのは難しいです)。 srcless iframeを作成すると、document.domainではなく、親ドキュメントのlocation.Hostからdocument.domainを受け取ります。その時点では、変更できないため、ほとんど失われています。

恐ろしい回避策は、srcをjavascript:URLに設定することです(いや!):

 iframe.src= "javascript:'<html><body><p>Hello<\/p><script>do things;<\/script>'";

しかし、何らかの理由で、そのようなドキュメントはIE(古き良き「不特定のエラー」)内のスクリプトから独自のdocument.domainを設定できないため、それを使用してブリッジを取り戻すことはできません親(*)。 couldそれを使用してドキュメント全体のHTMLを記述します。ウィジェットがインスタンス化されると、ウィジェットは親ドキュメントと通信する必要がないと仮定します。

ただし、iframe JavaScript URLはSafariで機能しないため、使用する方法を選択するには、何らかのブラウザスニッフィングが必要です。

*:他の何らかの理由で、can、IEでは、2番目のドキュメント、最初のドキュメントによってdocument.writtenからdocument.domainを設定します。だからこれは動作します:

if (isIE)
    iframe.src= "javascript:'<script>window.onload=function(){document.write(\\'<script>document.domain=\\\""+document.domain+"\\\";<\\\\/script>\\');document.close();};<\/script>'";

この時点で、私にとって恐ろしいレベルは高すぎます。 Davidが言ったように、外部HTMLを実行します。

66
bobince

はい、アクセス例外は、document.domainが親とiframeで一致する必要があるという事実によるものであり、一致する前に、iframeのdocument.domainプロパティをプログラムで設定することはできません。

ここでの最良の選択肢は、ページに独自のテンプレートを指定することです。

iframe.src = '/myiframe.htm#' + document.domain;

そしてmyiframe.htmで:

document.domain = location.hash.substring(1);
18
David Hedlund

よく私は実際に非常に似た問題を抱えていますが、ひねりを加えて...トップレベルサイトがa.foo.comであると言う-今私はドキュメントドメインをa.foo.comに設定します

その後、私が作成/所有するiframeで、a.foo.comも設定します

私はそれらをあまりにもfoo.com b/cに設定できないことに注意してください.b.a.foo.comを指すページに別のiframeがあります(再びa.foo.comを使用しますが、スクリプトコードを変更することはできません)

あなたは本質的にdocument.domainをすでにそれがすでにあるものに設定することに注意してください...しかし、私はb.a.foo.comから言及した他のiframeにアクセスするためにそれをしなければなりません

私のフレーム内で、ドメインを設定した後、すべてのiframeの設定が同じであっても、IE 6/7で親に到達するとエラーが発生します

本当に奇妙なことは他にもあります

外部/トップレベルで、onloadイベントを待ってタイマーを設定すると、最終的にアクセスする必要があるフレームに到達できます....しかし、ボトムアップから到達することはできません...そして私は本当にできる必要がある

また、すべてをfoo.comに設定した場合(これはできないと言ったように)、それは動作します!しかし、何らかの理由で、location.Host。と同じ値を使用する場合、それはありません。

3
Sean

iEの場合、ポートが重要です。ドメイン間では、同じポートである必要があります。

2
lwpro2

私は<iframe src="about:blank" ...></iframe>を使用するだけで、問題なく動作します。

2
jlcooke

私は同様の問題があり、私の解決策はこのコードスニペットでした(IE8/9、ChromeおよびFirefoxでテスト済み)

var iframe = document.createElement('iframe');
document.body.appendChild(iframe);

iframe.src = 'javascript:void((function(){var script = document.createElement(\'script\');' +
  'script.innerHTML = "(function() {' +
  'document.open();document.domain=\'' + document.domain +
  '\';document.close();})();";' +
  'document.write("<head>" + script.outerHTML + "</head><body></body>");})())';

iframe.contentWindow.document.write('<div>foo</div>');

私はいくつかの方法を試しましたが、これが最良のようです。私のブログ投稿でいくつかの説明を見つけることができます こちら

1
Zoltan Kochan

jQuery.contents() を試しましたか?

1
Deniss Kozlovs

Document.framesオブジェクトを介してiframeにアクセスしようとすると、IEの問題が発生するようです。作成したiframeへの参照を変数に保存すると、挿入したiframeに変数を介してアクセスできます(以下のコードのmy_iframe)。

IE6/7/8で動作するようになりました

var my_iframe;
var iframeId = "my_iframe_name"
if (navigator.userAgent.indexOf('MSIE') !== -1) {
  // IE wants the name attribute of the iframe set
  my_iframe = document.createElement('<iframe name="' + iframeId + '">');
} else {
  my_iframe = document.createElement('iframe');
}

iframe.setAttribute("src", "javascript:void(0);");
iframe.setAttribute("scrolling", "no");
iframe.setAttribute("frameBorder", "0");
iframe.setAttribute("name", iframeId);

var is = iframe.style;
is.border = is.width = is.height = "0px";

if (document.body) {
  document.body.appendChild(my_iframe);
} else {
  document.appendChild(my_iframe);
}
1
user299340

Andralorの非常に簡単な方法に従って、この問題を修正しました: https://github.com/fancyapps/fancyBox/issues/766

基本的に、更新時にiframeを再度呼び出します。

$('a.js-fancybox-iframe').fancybox({
    type: 'iframe',
    scrolling : 'visible',
    autoHeight: true,
    onUpdate: function(){
     $("iframe.fancybox-iframe");
   }
 });
1
Tim Denison