>웹 프론트엔드 >JS 튜토리얼 >JavaScript_javascript 기술의 두 가지 도메인 간 기술에 대한 포괄적인 소개

JavaScript_javascript 기술의 두 가지 도메인 간 기술에 대한 포괄적인 소개

WBOY
WBOY원래의
2016-05-16 16:52:101335검색

이 정책은 JavaScript 코드가 액세스할 수 있는 페이지 콘텐츠에 중요한 제한을 둡니다. 즉, JavaScript는 해당 콘텐츠가 포함된 문서와 동일한 도메인에 있는 콘텐츠에만 액세스할 수 있습니다.

JavaScript 보안 전략은 Ajax 프로그래밍뿐만 아니라 다중 iframe 또는 다중 창 프로그래밍을 수행할 때 특히 중요합니다. 이 정책에 따르면 baidu.com 아래의 페이지에 포함된 JavaScript 코드는 google.com 도메인 이름 아래의 페이지 콘텐츠에 액세스할 수 없습니다. 심지어 서로 다른 하위 도메인 사이의 페이지도 JavaScript 코드를 통해 서로 액세스할 수 없습니다. Ajax에 미치는 영향은 XMLHttpRequest를 통해 구현된 Ajax 요청이 다른 도메인에 요청을 제출할 수 없다는 것입니다. 예를 들어 abc.example.com 아래의 페이지는 def.example.com 등에 Ajax 요청을 제출할 수 없습니다.

그러나 심층적인 프런트엔드 프로그래밍을 하다 보면 필연적으로 크로스 도메인 작업이 필요하게 되는데 이때 '동일 출처 정책'은 너무 가혹해집니다. 이 문서에서는 이 문제에 대해 크로스 도메인에 필요한 몇 가지 기술을 요약합니다.

아래에서는 두 가지 상황에서 교차 도메인 기술을 논의합니다. 먼저 서로 다른 하위 도메인에서 교차 도메인 기술을 논의하고 완전히 다른 도메인에서 교차 도메인 기술을 논의합니다.

(1) 다양한 하위 도메인의 교차 도메인 기술.

두 가지 문제를 별도로 논의하겠습니다. 첫 번째 문제는 다양한 하위 도메인에서 JavaScript 호출을 수행하는 방법이고, 두 번째 문제는 Ajax 요청을 다른 하위 도메인에 제출하는 방법입니다.

먼저 첫 번째 문제를 해결해 보겠습니다. example.com 도메인 아래에 abc.example.com과 def.example.com이라는 두 개의 서로 다른 하위 도메인이 있다고 가정해 보겠습니다. 이제 def.example.com 아래에 JavaScript 함수를 정의하는 페이지가 있다고 가정합니다.

코드 복사 코드는 다음과 같습니다. 다음:
function funcInDef() {
.....
}

abc.example.com 아래의 페이지에서 위 함수를 호출하려고 합니다. 논의하려는 abc.example.com 아래의 페이지가 iframe 형식으로 def.example.com 아래의 페이지에 포함되어 있다고 가정합니다. 이 경우 iframe에서 다음 호출을 시도할 수 있습니다.

코드 복사 코드는 다음과 같습니다.
window.top.funcInDef();

알겠습니다. 이 호출은 앞서 언급한 "동일 출처 정책"에 의해 금지되며 JavaScript 엔진은 직접 예외를 발생시킵니다.
위 호출을 구현하려면 두 페이지의 도메인 속성을 수정하면 됩니다. 예를 들어 abc.example.com 및 def.example.com 위의 두 페이지 상단에 다음 JavaScript 코드 조각을 추가할 수 있습니다.
코드 복사 코드는 다음과 같습니다.
document.domain = "example.com";

이렇게 하면 두 페이지가 동일한 도메인이 되어 이전 호출이 정상적으로 실행될 수 있습니다.

여기서 한 가지 주의할 점은 페이지의 document.domain 속성은 상위 도메인 이름(1차 도메인 이름 제외)으로만 설정할 수 있고 하위 도메인으로 설정할 수 없다는 것입니다. 현재 도메인 이름보다 더 깊습니다. 예를 들어, abc.example.com 페이지는 도메인을 example.com으로만 설정할 수 있고 sub.abc.example.com은 설정할 수 없으며 물론 첫 번째 수준 도메인 이름인 com으로 설정할 수는 없습니다.

위의 예에서는 두 페이지가 iframe 중첩 관계에 속하는 경우를 설명합니다. 두 페이지가 열린 관계와 열린 관계를 갖는 경우 원리는 완전히 동일합니다.

두 번째 문제인 Ajax 요청을 다른 하위 도메인에 제출하는 방법을 해결해 보겠습니다.
일반적으로 XMLHttpRequest 객체를 생성하기 위해 다음과 유사한 코드를 사용합니다.

코드 복사 코드는 다음과 같습니다. :
factories = [function() {
return new XMLHttpRequest();
},
function() {
return new ActiveXObject("Msxml2.XMLHTTP");
},
function() {
return new ActiveXObject("Microsoft.XMLHTTP");
}];
function newRequest() {
for (var i = 0; i & lt;factory.length; i ) {
try {
var Factory = Factory[i];
return Factory();
} catch(e) {}
}
null을 반환합니다.
}

위 코드는 IE6 시리즈 브라우저와의 호환성을 위해 ActiveXObject를 참조합니다. newRequest 함수를 호출할 때마다 새로 생성된 Ajax 객체를 얻은 다음 이 Ajax 객체를 사용하여 HTTP 요청을 보냅니다. 예를 들어, 다음 코드는 abc.example.com에 GET 요청을 보냅니다.
코드 복사 코드는 다음과 같습니다.

var request = newRequest();
request.open("GET", "http://abc.example.com" );
request.send(null);

위의 코드가 abc.example.com 도메인 이름의 페이지에 포함되어 있다고 가정하면 문제 없이 GET 요청이 성공적으로 전송될 수 있습니다. 그러나 이제 def.example.com으로 요청을 보내면 도메인 간 문제가 발생하고 JavaScript 엔진에서 예외가 발생합니다.
해결책은 교차 도메인 파일을 def.example.com 도메인 아래에 배치하고, 이 파일이 crossdomain.html이라고 가정한 다음 이전 newRequest 함수의 정의를 이 교차 도메인 파일로 이동하고 마지막으로 수정하는 것입니다. 문서의 도메인 값은 abc.example.com 도메인 아래 Ajax를 호출하는 페이지와 crossdomain.html 상단에

코드 복사 코드는 다음과 같습니다.
document.domain = "example.com";

cross- 도메인 파일을 사용하려면 abc.example.com 도메인 아래에 Ajax를 호출합니다. 페이지에 크로스 도메인 파일을 가리키는 숨겨진 iframe을 삽입합니다. 예:

코드를 복사합니다. 코드는 다음과 같습니다.


이때 abc.example.com 도메인 하위 페이지와 크로스 도메인 파일 crossdomain.html은 모두 동일한 하위에 있습니다. 도메인(example.com) abc.example.com 도메인 아래 페이지에서 crossdomain.html을 호출할 수 있습니다.

코드 복사 코드는 다음과 같습니다.
var request = window.frames["xd_iframe" ].newRequest();
이렇게 얻은 요청 객체는 http://def.example.com에 대한 HTTP 요청입니다.

(2) 완전히 다른 도메인의 크로스 도메인 기술.

최상위 도메인 이름이 다른 경우, 예를 들어 example1.com과 example2.com이 JavaScript를 통해 프런트 엔드에서 통신하려는 경우 필요한 기술은 더 복잡합니다.


서로 다른 도메인의 크로스 도메인 기술을 설명하기 전에 먼저 아래에서 논의할 기술이 서로 다른 하위 도메인에 걸친 이전 상황에도 적용 가능하다는 점을 분명히 하겠습니다. 도메인 간 문제의 특별한 경우입니다. 물론, 올바른 상황에서 올바른 기술을 사용하면 더 나은 효율성과 더 높은 안정성을 보장할 수 있습니다.

요컨대 크로스 도메인 기술은 다양한 크로스 도메인 요구 사항에 따라 다음 범주로 분류될 수 있습니다.
1. JSONP 크로스 도메인 GET 요청
2. iframe
3. 플래시 크로스 도메인 HTTP 요청
4. window.postMessage
아래에서는 다양한 기술을 자세히 소개합니다.

1.JSONP.
페이지에 <script> 노드를 생성하여 다른 도메인에 HTTP 요청을 제출하는 방법을 JSONP라고 합니다. 이 기술은 도메인 간에 Ajax 요청을 제출하는 문제를 해결할 수 있습니다. JSONP의 작동 원리는 다음과 같습니다. </strong> GET 요청이 http://example1.com/index.php 페이지의 http://example2.com/getinfo.php에 제출되었다고 가정하면, 다음 JavaScript 코드를 http://example1.com/index.php 페이지에 배치하여 구현하세요. <br><br></p> <div class="codetitle"><span><a style="CURSOR: pointer" data="91817" class="copybut" id="copybut91817" onclick="doCopy('code91817')">코드 복사<u></u></a> 코드는 다음과 같습니다:</span></div>var eleScript= document.createElement("script");<div class="codebody" id="code91817">eleScript.type = "text/javascript";<br>eleScript.src = "http://example2. com/getinfo.php"; <br>document.getElementsByTagName("HEAD")[0].appendChild(eleScript);<br> <p>当GET请求从http://example2.com/getinfo.php返回时,可以返回一段JavaScript代码,这段代码会自动执行,可以用来负责调用http://example1.com/index.php页面中的一个callback函数。<br><br>JSONP的优点是:它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制;它的兼容性更好,在更加古老的浏览器中都可以运行,不需要XMLHttpRequest或ActiveX的支持;并且在请求完毕后可以通过调用callback的方式回传结果。<br><br>JSONP的缺点则是:它只支持GET请求而不支持POST等其它类型的HTTP请求;它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。</p> <p><strong>2. 通过iframe实现跨域。<br><br></strong>iframe跨域的方式,功能强于JSONP,它不仅能用来跨域完成HTTP请求,还能在前端跨域实现JavaScript调用。因此,完全不同域的跨域问题,通常采用iframe的方式来解决。<br><br>与JSONP技术通过创建<script>节点向不同的域提交GET请求的工作方式类似,我们也可以通过在http://example1.com/index.php页面中创建指向http://example2.com/getinfo.php的iframe节点跨域提交GET请求。然而,请求返回的结果无法回调http://example1.com/index.php页面中的callback函数,因为受到“同源策略”的影响。<br><br>为了解决这个问题,我们需要在example1.com下放置一个跨域文件,比如路径是http://example1.com/crossdomain.html。<br><br>当http://example2.com/getinfo.php这个请求返回结果的时候,它大体上有两个选择。<br>第一个选择是,它可以在iframe中做一个302跳转,跳转到跨域文件http://example1.com/crossdomain.html,同时将返回结果经过URL编码之后作为参数缀在跨域文件URL后面,例如http://example1.com/crossdomain.html?result=<URL-Encoding-Content>。<br><br>另一个选择是,它可以在返回的页面中再嵌入一个iframe,指向跨域文件,同时也是将返回结果经过URL编码之后作为参数缀在跨域文件URL后面。<br><br>在跨域文件中,包含一段JavaScript代码,这段代码完成的功能,是从URL中提取结果参数,经过一定处理后调用原来的http://example1.com/index.php页面中的一个预先约定好的callback函数,同时将结果参数传给这个函数。http://example1.com/index.php页面和跨域文件是在同一个域下的,因此这个函数调用可以通过。跨域文件所在iframe和原来的http://example1.com/index.php页面的关系,在前述第一种选择下,后者是前者的父窗口,在第二种选择下,后者是前者的父窗口的父窗口。<br><br>根据前面的叙述,有了跨域文件之后,我们就可以实现通过iframe方式在不同域之间进行JavaScript调用。这个调用过程可以完全跟HTTP请求无关,例如有些站点可以支持动态地调整在页面中嵌入的第三方iframe的高度,这其实是通过在第三方iframe里面检测自己页面的高度变化,然后通过跨域方式的函数调用将这个变化告知父窗口来完成的。<br><br>既然利用iframe可以实现跨域JavaScript调用,那么跨域提交POST请求等其它类型的HTTP请求就不是难事。例如我们可以跨域调用目标域的JavaScript代码在目标域下提交Ajax请求(GET/POST/etc.),然后将返回的结果再跨域传原来的域。<br><br>使用iframe跨域,优点是功能强大,支持各种浏览器,几乎可以完成任何跨域想做的事情;缺点是实现复杂,要处理很多浏览器兼容问题,并且传输的数据不宜过大,过大了可能会超过浏览器对URL长度的限制,要考虑对数据进行分段传输等。</p> <p><strong>3. 利用flash实现跨域HTTP请求<br></strong><br>据称,flash在浏览器中的普及率高达90%以上。<br><br>flash代码和JavaScript代码之间可以互相调用,并且flash的“安全沙箱”机制与JavaScript的安全机制并不尽相同,因此,我们可以利用flash来实现跨域提交HTTP请求(支持GET/POST等)。<br>例如,我们用浏览器访问http://example1.com/index.php这个页面,在这个页面中引用了http://example2.com/flash.swf这个flash文件,然后在flash代码中向http://example3.com/webservice.php发送HTTP请求。<br><br>这个请求能否被成功发送,取决于在example3.com的根路径下是否放置了一个crossdomain.xml以及这个crossdomain.xml的配置如何。flash的“安全沙箱”会保证:仅当example3.com服务器在根路径下确实放置了crossdomain.xml文件并且在这个文件中配置了允许接受来自example2.com的flash的请求时,这个请求才能真正成功。下面是一个crossdomain.xml文件内容的例子:</p> <p></p> <div class="codetitle"> <span><a style="CURSOR: pointer" data="91153" class="copybut" id="copybut91153" onclick="doCopy('code91153')"><u>코드 복사</u></a></span> 코드는 다음과 같습니다.</div> <div class="codebody" id="code91153"> <br><?xml version="1.0" ?> <br><cross-domain-policy><br>  <allow-access-from domain="example2.com" /><br></cross-domain-policy><br> </div> <p><strong>4. window.postMessage<br></strong> window.postMessage는 HTML 표준의 다음 버전인 HTML5에서 지원되는 새로운 기능입니다. 현재 인터넷 기술의 급속한 발전으로 인해 브라우저 간 도메인 통신에 대한 요구가 점점 더 강력해지고 있으며, 마침내 HTML 표준에서는 도메인 간 통신을 고려하게 되었습니다. 그러나 현재 HTML5는 아직 초안일 뿐입니다. <br> window.postMessage는 도메인 간 직접 통신을 구현하는 안전한 방법입니다. 그러나 현재 모든 브라우저가 이를 지원하는 것은 아닙니다. Firefox 3, Safari 4 및 IE8만이 이 호출을 지원할 수 있습니다. <br><br>다른 창으로 메시지를 보내는 데 사용하는 호출 방법은 대략 다음과 같습니다.<br></p> <div class="codetitle"> <span><a style="CURSOR: pointer" data="66586" class="copybut" id="copybut66586" onclick="doCopy('code66586')"><u>코드 복사</u></a></span> 코드는 다음과 같습니다.</div> <div class="codebody" id="code66586">otherWindow.postMessage(message, targetOrigin);</div> <br>수신창에서는 보낸 메시지를 수신하기 위한 이벤트 처리 기능을 설정해야 합니다. <br> <div class="codetitle"> <span><a style="CURSOR: pointer" data="40287" class="copybut" id="copybut40287" onclick="doCopy('code40287')"><u>코드 복사</u></a></span> 코드는 다음과 같습니다.</div> <div class="codebody" id="code40287">window.addEventListener("message", receiveMessage, false);<br>function receiveMessage(event) {<br> if (event .origin !== "http://example.org:8080") return;<br>}</div> <br>메시지에는 데이터, 원본(보내는 창이 위치한 도메인의 실제 정보를 전달) 및 소스(보내는 창의 핸들을 나타냄). <br><br>보안 고려 사항: window.postMessage를 사용할 때 메시지의 원본 및 원본 속성을 사용하여 보낸 사람의 신원을 확인해야 합니다. 그렇지 않으면 XSS 취약점이 발생합니다. <br><br>window.postMessage는 iframe에서 구현한 크로스 도메인 기능만큼 강력하고 사용이 간편하고 효율적이지만, 현재 브라우저 호환성 측면에서 개선이 필요하다는 단점이 있습니다. <br><br>원문에 추가해야 할 점은 IE6 및 IE7에서는 Object 또는 Function에 할당할 수 있는 IE Opener의 취약점이 악용될 수 있다는 점과 postMessage 솔루션에 대한 보완 솔루션이 제공된다는 것입니다. <br>메인 페이지: <p></p> <div class="codetitle"> <span><a style="CURSOR: pointer" data="92626" class="copybut" id="copybut92626" onclick="doCopy('code92626')"><u>코드 복사</u></a></span> 코드는 다음과 같습니다.</div> <div class="codebody" id="code92626"> <br><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" ><br><html xmlns="http://www.w3.org/1999/xhtml"><br><head><br>    <title>CrossDomain</title><br>&lt ;/head><br><body><br>    <iframe src="http://sh-tanzhenlin/CrossDomain-child.html"<BR>       frameborder="0" visible="false" height=" 0" width="0" id="ifrChild"></iframe><br><br>    <script type="text/javascript"><br>        var child = document.getElementById("ifrChild" );<br>        var openerObject = {<br>                funcInParent:function(arg){<br>                 Alert(arg);<br>                  Alert('상위 페이지의 함수로 실행됨' );<br>                }<br> }<br><br>        if(! 'v1' && !'1'[0]){ //테스트 브라우저는 ie6 또는 ie7입니다.   <br>            //crack<br>            child.contentWindow.opener = openerObject;<br>        }<br>        else{<br>            //postMessage showtime<br>        }<br><br>        함수 onClick(){<br>               openerObject.funcInIframe('상위 페이지의 데이터') ;<br>        }<br>    </script>
   



사용 중인 iframe内嵌其它域下的页면:



复主代码 代码如下: