프로그래밍 방식으로 생성 된 <iframe>의 문서 개체에 액세스하려고 할 때 "액세스가 거부되었습니다."JavaScript 오류 (IE 전용)


80

JavaScript를 사용하여 <iframe> 요소를 만들고 DOM에 추가해야하는 프로젝트가 있습니다. 그런 다음 <iframe>에 콘텐츠를 삽입해야합니다. 제 3 자 웹 사이트에 삽입 될 위젯입니다.

페이지를로드하고 싶지 않기 때문에 <iframe>의 "src"속성을 설정하지 않았습니다. 오히려 CSS 또는 JavaScript가 상위 페이지와 충돌하지 않도록 삽입하는 콘텐츠를 격리 / 샌드 박스하는 데 사용됩니다. JSONP를 사용하여 서버에서 일부 HTML 콘텐츠를로드하고이 <iframe>에 삽입합니다.

한 가지 심각한 예외를 제외하고 잘 작동합니다. 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

답변:


67

document.domain 속성이 부모 페이지에 설정되어 있으면 Internet Explorer에서 "액세스가 거부되었습니다."라는 메시지가 표시됩니다.

한숨. 네, 이것은 IE 문제입니다 (버그? 이런 종류의 불쾌함에 대한 문서화 된 표준이 없기 때문에 말하기 어렵습니다). 당신이 srcless은 iframe을 만들 때 그것은 수신 document.domain부모 문서에서는의 location.host대신으로 document.domain. 그 시점에서 당신은 그것을 바꿀 수 없기 때문에 거의 잃었습니다.

끔찍한 해결 방법은 srcjavascript : URL (urgh!)로 설정하는 것입니다.

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

그러나 어떤 이유로 이러한 문서는 document.domainIE의 스크립트에서 자체적으로 설정할 수 없으므로 (오래된 "지정되지 않은 오류")이를 사용하여 부모 (*) 사이의 다리를 다시 얻을 수 없습니다. 당신은 할 수 인스턴스화 된 후에는 부모 문서에 이야기 할 필요가 없습니다 위젯을 가정, 전체 문서의 HTML을 작성하는 데 사용합니다.

그러나 iframe JavaScript URL은 Safari에서 작동하지 않으므로 사용할 방법을 선택하려면 여전히 일종의 브라우저 스니핑이 필요합니다.

* : 다른 이유로 IE에서는 첫 번째 문서에 의해 작성된 두 번째 문서 인 document.에서 설정할 수 있습니다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 일에 Jeff Tucker의 게시물을 확인하세요. iframe>의 "src"속성이 "javascript : void ((function () {document.open (); document.domain = \ 'tld.com \'; document.close ();}) ())"로 보입니다. 트릭을 수행하고 브라우저 간 방식으로 수행합니다. Safari (최소 v3 이상)에서도 작동합니다.
— Bungle

1
다음은 이전 의견을 보여주는 테스트 페이지입니다. troy.onespot.com/static/access_denied_test.html
— Bungle

1
오 좋은! 훨씬 낫습니다! 직접 수행하는 것이 흥미 롭습니다. 일반적으로 javascript : URL은 부모의 컨텍스트에서 실행되지만 iframe src의 경우에는 그렇지 않은 것 같습니다. void()함수가 이미을 반환하기 때문에 호출을 잃을 수도 있습니다 undefined.
— bobince

1
부수적으로 IE에서 iframe 위치를 유지하려고 시도하기 때문에 IE에서 페이지를 다시로드하는 동안 오류가 발생합니다. argh. 그 주위에 방법이 있다면 Dunno.
— bobince

1
@bobince : 오, 당신이 맞아요. 지적 해 주셔서 감사합니다. 처음에는 너무 흥분해서 재 장전 할 필요가 없었습니다. IE가 <iframe> 위치를 유지하려고한다는 것은 무엇을 의미합니까? 이 문제에 대한 해결책을 찾아야하므로 계속 게시 해 드리겠습니다. 발견 한 내용이 있으면 똑같이하십시오.
— Bungle

18

예, 액세스 예외는 document.domain부모와 iframe에서 일치해야 한다는 사실 때문이며, 일치하기 전에 iframe의 document.domain속성 을 프로그래밍 방식으로 설정할 수 없습니다 .

여기에서 가장 좋은 방법은 페이지를 자신의 템플릿으로 지정하는 것입니다.

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

그리고 myiframe.htm에서 :

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

3
고마워, 데이비드-확실한 제안으로 보이는 것에 감사하지만 마지막 수단이 아니라면이 접근 방식을 사용하지 않는 편입니다. 내가 올바르게 이해한다면 템플릿은 상위 페이지와 동일한 도메인에 있어야하며 (맞습니까?) 고객의 구현이 복잡해집니다. 이상적으로 구현은 페이지의 HTML에 몇 줄의 JavaScript를 삽입하는 것처럼 간단해야합니다.
— Bungle

1
예, 솔루션은 바로 그 도메인에 다른 파일이 필요합니다. 하지만 그것이 제가 생각 해낼 수있는 최선의 방법이 아닐까 두렵습니다.
— David Hedlund

1
@Bungle : 나는 그것이 당신의 유일한 선택이라고 생각합니다.
— Tim Down

3

글쎄, 나는 실제로 매우 비슷한 문제가 있지만 비틀어 ... 최상위 사이트가 a.foo.com이라고 말하십시오-이제 문서 도메인을 a.foo.com으로 설정했습니다.

그런 다음 내가 생성 / 소유 한 iframe에서 a.foo.com도 설정했습니다.

내가 너무 foo.com을 설정할 수 없다는 점에 유의하십시오 .b / c 페이지에 bafoo.com을 가리키는 다른 iframe이 있습니다 (다시 a.foo.com을 사용하지만 스크립트 코드를 변경할 수 없습니다)

당신은 본질적으로 document.domain을 어쨌든 이미 설정 한 것으로 설정한다는 것을 알 수 있습니다 ...하지만 bafoo.com에서 언급 한 다른 iframe에 액세스하려면 그렇게해야합니다.

내 프레임 내에서 도메인을 설정 한 후 모든 iframe이 동일한 설정을 갖더라도 IE 6/7에서 부모에 도달 할 때 여전히 오류가 발생합니다.

r 정말 비 자리 다른 것들이 있습니다

외부 / 최상위 수준에서 onload 이벤트를 기다렸다가 타이머를 설정하면 결국 액세스해야하는 프레임에 도달 할 수 있습니다 ....하지만 아래에서 위로 도달 할 수는 없습니다. 할 수 있어야

또한 모든 것을 foo.com으로 설정하면 (내가 말한대로 할 수 없습니다) 작동합니다! 그러나 어떤 이유로, location.host와 같은 값을 사용할 때 .... 그것은 나를 죽이는 것입니다 .....


2

나는 단지 사용 <iframe src="about:blank" ...></iframe>하고 잘 작동합니다.


2

IE의 경우 포트가 중요합니다. 도메인 간에는 동일한 포트 여야합니다.


1

jQuery.contents () 사용해 보셨습니까 ?


1
Deniss, 좋은 제안 및 감사합니다. 한 번 해보았 지만 (< troy.onespot.com/static/access_denied_jquery.html> 참조 ) 비슷한 오류가 발생했습니다. 이번에는 jQuery 스크립트 내에서 "Permission denied"입니다. 나는 그것이 동일하거나 유사한 장애물이라고 생각합니다.
— Bungle

1
죄송합니다. URL이 망가졌습니다. 시도 : troy.onespot.com/static/access_denied_jquery.html
— Bungle

4
jQuery가 iframe의 문서에 마법처럼 액세스 할 수있는 이유는 무엇입니까?
— Tim Down

8
@Tim Down : jQuery가 마법 같은 접근 권한을 가질 것이라는 가정은 생각하지 않습니다. 오히려 jQuery는 종종 브라우저 간 문제를 해결하기 위해 몇 가지 멋진 트릭을 가지고 있으며 이미 해결 방법을 구현했을 수 있습니다. 나는 그것이 좋은 징조가 아니라는 데 동의하지만 좋은 제안이었고 한 번의 가치가 있다고 생각합니다.
— Bungle

이것은 정말로 대답이 아닙니다. 제안 일 뿐이며 원래 게시물에 대한 댓글로 더 좋을 것입니다.
— Neil Monroe

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

1
이상한 점은 제가 사용하던 것과 똑같다는 것입니다. 잘 작동했습니다. 이제 갑자기 getttig access denied 오류가 계속 발생합니다
— frostymarvelous

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을 다시 onUpdate로 호출합니다.

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

-2

IE는 다른 모든 브라우저와 마찬가지로 iframe에서 작동합니다 (적어도 주요 기능의 경우). 규칙 세트를 유지하기 만하면됩니다.

  • iframe (iframe 부모에 대해 알아야하는 js 부분)에 자바 스크립트를로드하기 전에 부모가 document.domain이 변경되었는지 확인합니다.
  • 모든 iframe 리소스가로드되면 document.domain을 부모에 정의 된 것과 동일하게 변경합니다. (도메인을 설정하면 iframe 리소스의 요청이 실패하므로 나중에이 작업을 수행해야합니다.)

  • 이제 부모 창에 대한 참조를 만들 수 있습니다. var winn = window.parent

  • 이제 부모 HTML을 조작하기 위해 참조를 만들 수 있습니다. var parentContent = $ ( 'html', winn.document)
  • 이 시점에서 IE 부모 창 / 문서에 대한 액세스 권한이 있어야하며 원하지 않는대로 변경할 수 있습니다.

-11

나를 위해 더 나은 대답은 액세스가 거부되는 파일 허용을 확인하는 것입니다.

방금 jQuery-1.8.0.js로 업데이트하고 IE9에서 액세스 거부 오류가 발생했습니다.

Windows 탐색기에서

  • 속성을 선택한 파일을 마우스 오른쪽 버튼으로 클릭했습니다.
  • 보안 탭을 선택했습니다.
  • 고급 버튼을 클릭
  • 소유자 탭을 선택했습니다.
  • 편집 버튼을 클릭
  • 선택한 관리자 (MachineName \ Administrators)
  • 적용을 클릭
  • 모든 창문을 닫았습니다.

사이트를 테스트했습니다. 더 이상 문제가 없습니다.

방금 업데이트 한 jQuery-UI 스크립트에 대해서도 동일한 작업을 수행해야했습니다.


2
나는 당신이 다른 문제를 해결하고 있다고 생각합니다.
— Danyal Aytekin

5
OP는 타사 위젯을 구축하고 있습니다. 모든 방문자가 위젯을 표시하기 위해이 모든 단계를 따르기를 기대할 수는 없습니다.
— Christophe
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.