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


80

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>のウィンドウオブジェクトにハンドルがあります。そのドキュメントオブジェクトについて、これ以上深く理解することはできません。

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


troy.onespotへのリンクが切れています。
mbomb007 2018

回答:


67

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

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

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

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

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

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

*:他の理由で、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をやります。


10
@bobince:あなたは素晴らしいです!私は実際、もっとたくさんのグーグルをした後、昨夜遅くにこのアプローチにつまずきました。実際、私はさらに堅牢で、潜在的に厄介なクロスブラウザソリューションを見つけたかもしれないと思います:telerik.com/community/forums/aspnet-ajax/editor/…-8月21日からのJeffTuckerの投稿に注意してください。 iframe>の "src"属性から "javascript:void((function(){document.open(); document.domain = \ 'tld.com \'; document.close();})())"トリックを行うために、そしてクロスブラウザの方法で。Safari(少なくともv3 +)でも動作します。
バングル

1
これが私の以前のコメントを説明するテストページです:troy.onespot.com/static/access_denied_test.html
Bungle

1
それはいい!それははるかに良いです!それを直接行うことはうまくいくはずです...通常、javascript:URLはその親のコンテキストで実行されますが、iframesrcの場合はそうではないようです。void()関数はすでにを返すため、おそらく呼び出しを失う可能性もありますundefined
bobince 2009

1
ちなみに、IEがiframeの場所を保持しようとするため、これを使用してIEでページを再読み込みするとエラーが発生します... argh。それを回避する方法があれば、Dunno。
bobince 2009

1
@bobince:ああ、その通りです。それを指摘してくれてありがとう。私はとても興奮していたので、初めて動作したので、わざわざリロードする必要はありませんでした。IEが<iframe>の場所を保持しようとするとどういう意味ですか?私はこれに対する解決策を見つけなければならないので、私はあなたを投稿し続けます-何かを見つけた場合は同じことをしてください。
バングル

18

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

ここでの最善のオプションは、ページを独自のテンプレートにポイントすることだと思います。

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

そしてmyiframe.htmで:

document.domain = location.hash.substring(1);

3
おかげで、デビッド-確かな提案のように見えるものに感謝しますが、それが最後の手段でない限り、私はむしろこのアプローチを採用したくありません。私が正しく理解していれば、テンプレートは親ページと同じドメインに存在する必要があり(そうですか?)、それはお客様の実装を複雑にします。理想的には、実装はページのHTMLにJavaScriptを数行挿入するのと同じくらい簡単である必要があります。
バングル

1
はい、ソリューションにはそのドメインに別のファイルが必要です。でも、それが私が思いつくことができる最高のものだと思います。
David Hedlund

1
@バングル:それがあなたの唯一の選択肢だと思います。
ティムダウン

3

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

次に、私が作成/所有するiframeで、それもa.foo.comに設定します。

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

とにかく、基本的にdocument.domainをすでに設定していることに注意してください...しかし、bafoo.comから言及した他のiframeにアクセスするにはそれを行う必要があります

フレーム内で、ドメインを設定した後、すべてのiframeの設定が同じでも、IE6 / 7で親にアクセスするとエラーが発生します

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

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

また、すべてをfoo.comに設定した場合(私が言ったように、それはできません)、それは機能します!しかし、何らかの理由で、location.hostと同じ値を使用すると、そうではなく、そのおかしなことに私を殺してしまいます。


2

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


2

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


1

1
デニス、良い提案、そしてありがとう-私はこれを試してみましたが(< troy.onespot.com/static/access_denied_jquery.html>を参照)、同様のエラーが発生しました。今回は、jQueryスクリプト内の「アクセスが拒否されました」です。私はそれが同じまたは同様の障害であると思います。
バングル

1
申し訳ありませんが、そのURLは壊れています。試してみてください:troy.onespot.com/static/access_denied_jquery.html
バングル

4
jQueryがiframeのドキュメントに魔法のようにアクセスできるのはなぜですか?
ティムダウン

8
@Tim Down:jQueryが魔法のようにアクセスできるとは思いませんでした。むしろ、jQueryには、クロスブラウザーの問題を解決するための巧妙なトリックが含まれていることが多く、すでに回避策が実装されている可能性があります。私はそれが良い前兆ではなかったことに同意しますが、それは良い提案であり、一撃の価値があると思います。
バングル

これは本当に答えではありません。これは単なる提案であり、元の投稿へのコメントとしてはおそらく良いでしょう。
ニールモンロー

1

IEの問題は、document.framesオブジェクトを介してiframeにアクセスしようとすると発生するようです-作成されたiframeへの参照を変数に格納すると、変数(以下のコードのmy_iframe)を介して挿入された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
ありがとう。これで問題は解決したようです。
vit 2011

1
奇妙なことに、これは私が使っていたものと同じものでした。正常に動作していましたが、突然、getttigアクセス拒否エラーが発生し続けます
frostymarvelous 2013

1

同様の問題があり、解決策はこのコードスニペットでした(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

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

-2

IEは、他のすべてのブラウザーと同様にiframeで動作します(少なくとも主な機能について)。一連のルールを維持する必要があります。

  • iframe(iframeの親について知る必要があるjsの部分)にJavaScriptをロードする前に、親のdocument.domainが変更されていることを確認してください。
  • すべてのiframeリソースが読み込まれたら、document.domainを親で定義されているものと同じになるように変更します。(ドメインを設定するとiframeリソースのリクエストが失敗するため、後でこれを行う必要があります)

  • これで、親ウィンドウの参照を作成できます。varwinn = window.parent

  • これで、親HTMLを操作するために、親HTMLへの参照を作成できます。varparentContent= $( 'html'、winn.document)
  • この時点で、IEの親ウィンドウ/ドキュメントにアクセスできるはずです。変更することはできません。

-11

私にとってより良い答えは、アクセスが拒否されているファイルの許可を確認することでした。

jQuery-1.8.0.jsに更新したところ、IE9でアクセス拒否エラーが発生していました。

Windowsエクスプローラーから

  • プロパティを選択したファイルを右クリックしました
  • [セキュリティ]タブを選択しました
  • 詳細ボタンをクリックしました
  • [所有者]タブを選択しました
  • 編集ボタンをクリック
  • 選択した管理者(MachineName \ Administrators)
  • [適用]をクリックしました
  • すべてのウィンドウを閉じました。

サイトをテストしました。これ以上の問題はありません。

更新したばかりのjQuery-UIスクリプトについても同じことをしなければなりませんでした


2
あなたは別の問題を解決していると思います。
Danyal Aytekin 2012年

5
OPはサードパーティのウィジェットを構築しています。すべての訪問者がこれらすべての手順に従ってウィジェットを表示することを期待することはできません。
クリストフ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.