>웹 프론트엔드 >JS 튜토리얼 >프런트엔드 교차 도메인 요약에 대한 관련 지식 포인트

프런트엔드 교차 도메인 요약에 대한 관련 지식 포인트

jacklove
jacklove원래의
2018-05-21 16:41:221567검색

이 문서에서는 크로스 도메인에 대한 관련 설명을 제공합니다.

머리말

다양한 프런트엔드 크로스 도메인 솔루션은 정말 어지러울 정도입니다. 이런 회사 면접 장면을 본 적이 있는데, 여러 사람이 함께 면접을 기다리고 있었는데, 면접관이 "크로스 도메인 솔루션에 대해 알려주세요."라고 묻더군요((3종). 그때 기억나는 것), 면접관이 "들어올 때 다들 이 세 가지를 말했어요. 이거 말고 또 뭐가 있나요?"라고 했더니 갑자기 바람에 엉망이 됐다. .. 이 경우 부족한 점을 확인하고 메우기 위해 블로그를 혼자서 요약할 수 밖에 없습니다.

1. 크로스도메인이란 무엇인가요?

크로스 도메인이라는 단어는 말 그대로 크로스 도메인 이름을 의미하지만 실제로 크로스 도메인의 범위는 그다지 좁지 않습니다. 구체적인 개념은 다음과 같습니다. 프로토콜, 도메인 이름, 포트가 서로 다른 한 서로 다른 도메인으로 간주됩니다. 크로스 도메인 문제가 발생하는 이유는 사실 이해하기 쉽습니다. 외부 파일을 아무렇게나 참조하고, 서로 다른 태그의 페이지가 유사한 파일을 참조하면 브라우저가 쉽게 혼란스러워지고 보안이 단번에 보장되지 않습니다. 모든 것에는 안전이 최우선입니다. 그러나 보안 제한 외에도 iframe 또는 ajax 애플리케이션을 주입하는 데 많은 문제가 발생합니다. 따라서 이 도메인의 js가 다른 도메인의 페이지 개체를 작동할 수 있도록 하거나 다른 도메인의 js가 이 도메인의 페이지 개체(iframe 간)를 작동할 수 있도록 하려면 몇 가지 방법을 사용해야 합니다. 다음은 특정 도메인 간 상황에 대한 자세한 설명입니다.           통신 허용 여부

http://www.a.com/a.jshttp://www.a.com/b.js 동일한 도메인 이름으로 http://www.a.com/b.js :// 허용됨 www.a.com/lab/a.jshttp://www.a.com/script/b.js 동일한 도메인 이름 아래에 다른 폴더가 허용됨 http://www.a.com:8000 /a.jshttp:// www.a.com/b.js 동일한 도메인 이름, 다른 포트는 허용되지 않습니다. http://www.a.com/a.js https://www.a.com/b .js 동일한 도메인 이름, 다른 프로토콜은 허용되지 않습니다 http: //www.a.com/a.jshttp://70.32.92.74/b.js 도메인 이름과 도메인 이름에 해당하는 IP는 허용되지 않습니다 http ://www.a.com/a.jshttp://script.a.com/ b.js 동일한 기본 도메인, 다른 하위 도메인 허용되지 않음(이 경우 쿠키 접근이 허용되지 않음) http://www. a.com/a.jshttp://a.com/b.js 같은 도메인 이름, 다른 2차 도메인 이름(위와 동일) 허용하지 않음(이 경우 쿠키 접근이 허용되지 않음) http:// www.cnblogs.com/a.jshttp://www.a.com/b.js 다른 도메인 이름은 허용되지 않습니다



두 가지 사항에 유의해야 합니다.

교차 도메인 문제가 프로토콜 및 포트, "프론트 데스크"는 무력합니다.

도메인 간 문제의 경우 동일한 IP 주소가 두 도메인에 해당하는지 또는 두 도메인이 포트에 있는지 여부를 판단하지 않고 "URL 헤더"로만 도메인을 식별합니다. 동일한 IP.

("URL 헤더"는 window.location.protocol +window.location.host를 의미하며, 이는 "도메인, 프로토콜 및 포트가 일치해야 합니다"라고도 이해할 수 있습니다.)


동일 출처 정책

동일 도메인 이름(또는 IP) ), 동일한 포트 및 프로토콜은 동일한 도메인에 있는 것으로 간주됩니다. 도메인의 스크립트는 이 도메인 내에서만 권한을 갖습니다. 이 도메인의 스크립트는 이 도메인의 리소스를 읽고 쓸 수만 있고 리소스에 액세스할 수 없다는 것을 이해할 수 있습니다. 다른 도메인에서. 이 보안 제한을 동일 출처 정책이라고 합니다.

동일 출처 정책은 브라우저의 가장 기본적인 보안 기능입니다. 동일 출처 정책이 없으면 일반 사용자에게는 보안이 전혀 없습니다. 웹사이트 쿠키, 이메일 콘텐츠 등 사용자의 모든 개인정보는 누구든지 얻을 수 있습니다. CSRF 공격에도 취약합니다.

도메인 이름과 도메인 이름에 해당하는 IP는 서로 다른 출처에서 온 것입니다. 기본 도메인 이름이 동일한 경우 하위 도메인 이름도 다른 출처에서 온 것입니다.

교차 도메인 솔루션(요약)

1. document.domain 교차 도메인

앞서 언급했듯이 브라우저에는 동일 원본 정책이 있으며, 그 제한 중 하나는 ajax 방식을 통해 다른 소스의 문서를 요청할 수 없다는 것입니다. 두 번째 제한은 js가 브라우저의 다른 도메인에 있는 프레임 간에 상호 작용할 수 없다는 것입니다.
window 개체는 서로 다른 프레임워크 간에 얻을 수 있지만 해당 속성과 메서드는 얻을 수 없습니다.
예를 들어 페이지가 있고 주소는 http://www.damonare.cn/a.html이고 이 페이지에는 iframe이 있으며 src는 http://damonare.cn/b.html입니다. 분명히 이 페이지와 그 안에 있는 iframe은 서로 다른 도메인에 있으므로 다음과 같이 페이지에 js 코드를 작성하여 iframe에 있는 항목을 가져올 수 없습니다.

<script type="text/javascript">
    function test(){        var iframe = document.getElementById(&#39;ifame&#39;);
   var win = document.contentWindow; //可以获取到iframe里的window对象,但该window对象的属性和方法几乎是不可用的
        var doc = win.document; //这里获取不到iframe里的document对象
        var name = win.name; //这里同样获取不到window对象的name属性
    }</script><iframe id = "iframe" src="http://damonare.cn/b.html" onload = "test()"></iframe>

이때 document.domain이 유용할 수 있습니다. http://www.damonare.cn/a.html 및 http://damonare.cn/b.html 두 페이지의 document.domain을 동일한 도메인 이름으로 설정하기만 하면 됩니다.

참고: document.domain 설정은 제한되어 있습니다. document.domain은 자체 도메인이나 상위 도메인으로만 설정할 수 있으며 기본 도메인은 동일해야 합니다.

document.domain:

<iframe id = "iframe" src="http://damonare.cn/b.html" onload = "test()"></iframe><script type="text/javascript">
    document.domain = &#39;damonare.cn&#39;;//设置成主域
    function test(){        //contentWindow 可取得子窗口的 window 对象
        alert(document.getElementById(&#39;iframe&#39;).contentWindow);
    }</script>

http://www.damonare.cn/a.html 페이지에서 document.domain:

aaa0337ea682bd8a606d045f2876fe38
문서도 설정하세요. domain = 'damonare.cn';//iframe에서 이 페이지를 로딩할 때 document.domain도 메인 페이지의 document.domain과 동일하게 설정하세요2cacc6d41bbb37262a98f745aa00fbf0

문서 수정 방법. 도메인은 서로 다른 하위 도메인의 프레임 간 상호 작용에만 적용 가능합니다.

2. location.hash를 통한 도메인 간

부모 창은 iframe의 URL을 읽고 쓸 수 있고, iframe도 부모 창의 URL을 읽고 쓸 수 있기 때문에 URL의 일부를 해시라고 합니다. 이는 # 기호와 그 뒤의 문자입니다. 일반적으로 브라우저 앵커 위치 지정에 사용됩니다. HTTP 요청 프로세스에서는 해시가 전달되지 않으므로 수정이 필요합니다. 이 부분은 HTTP 요청을 생성하지 않지만 브라우저 기록 레코드를 생성합니다. 이 방법의 원리는 양방향 통신을 위해 URL의 해시 부분을 변경하는 것입니다. 각 창은 다른 창의 위치를 ​​변경하여 메시지를 보냅니다(두 페이지가 동일한 도메인에 있지 않기 때문에 IE와 Chrome은 parent.location.hash 값 수정을 허용하지 않으므로 상위 창이 필요함) 그리고 자신의 URL 변경 사항을 수신하여 메시지를 받습니다. 이 통신 방법은 불필요한 브라우저 기록을 발생시킬 수 있으며, 일부 브라우저는 onhashchange 이벤트를 지원하지 않으며 URL 변경 사항을 알아보기 위해 폴링해야 합니다. 마지막으로 이 방법에도 데이터가 URL에 직접 노출되는 등의 단점이 있습니다. 용량과 종류가 제한되어 있습니다.

예:
상위 페이지가 baidu.com/a.html이고 iframe에 포함된 페이지가 google.com/b.html인 경우(여기서는 도메인 이름 및 기타 URL 속성이 생략됨), 둘 사이의 통신 페이지를 달성해야 합니다. 다음 방법을 사용할 수 있습니다.

a.html 데이터를 b.html로 전송하고

a.html iframe의 src를 google.com/b.html#paco로 수정

b.html URL의 변경 사항을 모니터링하고 해당 작업을 실행합니다.

b.html은 데이터를 a.html로 전송합니다. 두 페이지가 동일한 도메인에 있지 않기 때문에 IE와 Chrome에서는 parent.location.hash 값을 허용하지 않습니다. 수정되었으므로 상위 창의 도메인 이름 아래에 있는 프록시 iframe을 사용해야 합니다

b .html 아래에 숨겨진 iframe을 생성합니다. 이 iframe의 src는 baidu.com 도메인 아래에 있고 전송할 해시 데이터를 첨부합니다. src="http://www.baidu.com/proxy.html#data"

proxy.html은 URL 변경을 모니터링하고 a.html의 URL을 수정합니다(a.html 및 *proxy.html이 동일한 도메인이므로 Proxy.html은 a.html의 URL 해시를 수정할 수 있습니다)

a.html은 URL 변경을 모니터링하고 해당 작업을 트리거합니다. b.html 페이지의 키 코드는 다음과 같습니다.

try {  
    parent.location.hash = &#39;data&#39;;  
} catch (e) {  
    // ie、chrome的安全机制无法修改parent.location.hash,  
    var ifrproxy = document.createElement(&#39;iframe&#39;);  
    ifrproxy.style.display = &#39;none&#39;;  
    ifrproxy.src = "http://www.baidu.com/proxy.html#data";  
    document.body.appendChild(ifrproxy);  
}

The Proxy.html 페이지의 키 코드는 다음과 같습니다:

/**

*parent.parent(예: baidu.com/a.html)와 baidu.com/proxy.html은 동일한 도메인에 속하므로

location.hash의 값이 변경될 수 있습니다**/ parent.parent.location.hash = self.location.hash.substring(1);


3. HTML5 postMessage 방법

고급 브라우저 IE8+, Chrome, Firefox, Opera 및 Safari는 모두 이 기능을 지원합니다.

이 기능에는 주로 정보를 수신하는 "message" 이벤트와 메시지를 보내는 "postMessage" 메서드가 포함됩니다.

예를 들어 damonare.cn 도메인의 페이지 A는 iframe을 통해 google.com 도메인의 페이지 B를 삽입합니다. A와 B 간의 통신은 다음 방법을 통해 이루어질 수 있습니다.

페이지 A는 postMessage 메소드를 통해 메시지를 보냅니다.

window.onload = function() {  
    var ifr = document.getElementById(&#39;ifr&#39;);  
    var targetOrigin = "http://www.google.com";  
    ifr.contentWindow.postMessage(&#39;hello world!&#39;, targetOrigin);  
};

postMessage 사용 방법 :otherWindow.postMessage(message, targetOrigin);

otherWindow: 대상 창, 즉 메시지가 전송되는 창을 나타냅니다. window.frames 속성의 멤버입니다. window.open 메소드로 생성된 창.

message: 전송할 메시지이며 유형은 String, Object입니다(IE8 및 9에서는 지원되지 않음).

targetOrigin: 메시지 수신 범위를 제한합니다. 제한이 없는 경우 '*'를 사용하세요.

페이지 B는 메시지 이벤트를 통해 메시지를 듣고 수락합니다.

var onmessage = function (event) {  
  var data = event.data;//消息  
  var origin = event.origin;//消息来源地址  
  var source = event.source;//源Window对象  
  if(origin=="http://www.baidu.com"){  
console.log(data);//hello world!  
  }  
};  
if (typeof window.addEventListener != &#39;undefined&#39;) {  
  window.addEventListener(&#39;message&#39;, onmessage, false);  
} else if (typeof window.attachEvent != &#39;undefined&#39;) {  
  //for ie  
  window.attachEvent(&#39;onmessage&#39;, onmessage);  
}

마찬가지로 페이지 B도 메시지를 보낼 수 있으며, 페이지 A는 메시지를 듣고 수락합니다.

4.jsonp 크로스 도메인

以上的这几种都是双向通信的,即两个iframe,页面与iframe,或是页面与页面之间的。
下面说几种单向跨域的(一般用来获取数据),因为通过script标签引入的js是不受同源策略的限制的。
所以我们可以通过script标签引入一个js或者是一个其他后缀形式(如php,jsp等)的文件,此文件返回一个js函数的调用。

比如,有个a.html页面,它里面的代码需要利用ajax获取一个不同域上的json数据,假设这个json数据地址是http://damonare.cn/data.php,那么a.html中的代码就可以这样:

5cd6e472395e766622bc5d31b556eb7a
   function dosomething(jsondata){        //处理获得的json数据
   }2cacc6d41bbb37262a98f745aa00fbf0c94d748985e78489742ad0fcf1c2ee3a2cacc6d41bbb37262a98f745aa00fbf0

可以看到获取数据的地址后面还有一个callback参数,按惯例是用这个参数名,但是你用其他的也一样。当然如果获取数据的jsonp地址页面不是你自己能控制的,就得按照提供数据的那一方的规定格式来操作了。
因为是当做一个js文件来引入的,所以http://damonare.cn/data.php返回的必须是一个能执行的js文件,所以这个页面的php代码可能是这样的(一定要和后端约定好哦):

4186f33f23dde584c80c610ba061e215

最终,输出结果为:dosomething([‘a’,’b’,’c’]);

如果你的页面使用jquery,那么通过它封装的方法就能很方便的来进行jsonp操作了:

<script type="text/javascript">
    $.getJSON(&#39;http://example.com/data.php?callback=?,function(jsondata)&#39;){        //处理获得的json数据
    });</script>

jquery会自动生成一个全局函数来替换callback=?中的问号,之后获取到数据后又会自动销毁,实际上就是起一个临时代理函数的作用。
$.getJSON方法会自动判断是否跨域,不跨域的话,就调用普通的ajax方法;跨域的话,则会以异步加载js文件的形式来调用jsonp的回调函数。

JSONP的优缺点:

JSONP的优点:
它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制;它的兼容性更好,在更加古老的浏览器中都可以运行,不需要XMLHttpRequest或ActiveX的支持;并且在请求完毕后可以通过调用callback的方式回传结果。

JSONP的缺点:
它只支持GET请求而不支持POST等其它类型的HTTP请求;它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。

5. CORS跨域

CORS(Cross-Origin Resource Sharing)跨域资源共享,定义了必须在访问跨域资源时,浏览器与服务器应该如何沟通。
CORS背后的基本思想就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功还是失败。
目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。整个CORS通信过程,都是浏览器自动完成,不需要用户参与。
对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。

因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

平时的ajax请求可能是这样的:

<script type="text/javascript">
    var xhr = new XMLHttpRequest();
    xhr.open("POST", "/damonare",true);
    xhr.send();</script>

以上damonare部分是相对路径,如果我们要使用CORS,相关Ajax代码可能如下所示:

<script type="text/javascript">
    var xhr = new XMLHttpRequest();
    xhr.open("GET", "http://segmentfault.com/u/andreaxiang/",true);
    xhr.send();</script>

代码与之前的区别就在于相对路径换成了其他域的绝对路径,也就是你要跨域访问的接口地址。

服务器端对于CORS的支持,主要就是通过设置Access-Control-Allow-Origin来进行的。
如果浏览器检测到相应的设置,就可以允许Ajax进行跨域的访问。
关于CORS更多了解可以看下阮一峰老师的这一篇文章:跨域资源共享 CORS 详解

CORS和JSONP对比

JSONP只能实现GET请求,而CORS支持所有类型的HTTP请求。

使用CORS,开发者可以使用普通的XMLHttpRequest发起请求和获得数据,比起JSONP有更好的错误处理。

JSONP主要被老的浏览器支持,它们往往不支持CORS,而绝大多数现代浏览器都已经支持了CORS。

CORS与JSONP相比,无疑更为先进、方便和可靠。

6. 通过window.name跨域

window对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的,并不会因新页面的载入而进行重置。
比如:我们在任意一个页面输入

window.name = "My window&#39;s name";
setTimeout(function(){    window.location.href = "http://damonare.cn/";
},1000)

进入damonare.cn页面后我们再检测再检测 window.name :
window.name; // My window's name

可以看到,如果在一个标签里面跳转网页的话,我们的 window.name 是不会改变的。
基于这个思想,我们可以在某个页面设置好 window.name 的值,然后跳转到另外一个页面。在这个页面中就可以获取到我们刚刚设置的 window.name 了。

由于安全原因,浏览器始终会保持 window.name 是string 类型。

同样这个方法也可以应用到和iframe的交互来,比如:
我的页面(http://damonare.cn/index.html)中内嵌了一个iframe:
513d18592b18dd8843237d23f841aa01065276f04003e4622c4fe6b64f465b88

在 iframe.html 中设置好了 window.name 为我们要传递的字符串。
我们在 index.html 中写了下面的代码:

var iframe = document.getElementById(&#39;iframe&#39;);var data = &#39;&#39;;
iframe.onload = function() {
    data = iframe.contentWindow.name;
};

报错!肯定的,因为两个页面不同源嘛,想要解决这个问题可以这样干:

var iframe = document.getElementById(&#39;iframe&#39;);var data = &#39;&#39;;
 
iframe.onload = function() {
    iframe.onload = function(){
        data = iframe.contentWindow.name;
    }
    iframe.src = &#39;about:blank&#39;;
};

或者将里面的 about:blank 替换成某个同源页面(about:blank,javascript: 和 data: 中的内容,继承了载入他们的页面的源。)

这种方法与 document.domain 方法相比,放宽了域名后缀要相同的限制,可以从任意页面获取 string 类型的数据。

本篇对跨域做出相应的总结,更多相关知识请关注php中文网。

相关推荐:

前端常见跨域解决方案(全)

什么是跨域?跨域有几种实现形式?

对于函数事件的总结

위 내용은 프런트엔드 교차 도메인 요약에 대한 관련 지식 포인트의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.