This article provides relevant explanations about cross-domain.
Preface
The variety of front-end cross-domain solutions is really dizzying. I once encountered a company interview scene like this. Several people were waiting for the interview together. They went in one by one. The interviewer asked: "Tell me about a cross-domain solution.", and he said it ( (Three kinds that I could remember in my mind at that time), and then the interviewer said: "Each of you said these three when you came in. Apart from these, what else are there?", and it was suddenly messy in the wind... In this case, I can only summarize a blog by myself in order to check and fill in the gaps.
1. What is cross-domain?
The word cross-domain literally means cross-domain name, but in fact the scope of cross-domain is definitely not that narrow. The specific concept is as follows: As long as the protocol, domain name, and port are different, they are regarded as different domains. The reason why cross-domain problems arise is actually easy to understand. If external files are referenced casually, and pages under different tags reference similar files to each other, the browser will easily become confused, and security will not be guaranteed. At once. In everything, safety comes first. However, in addition to security restrictions, it also brings a lot of trouble to injecting iframe or ajax applications. Therefore, we need to use some methods to enable js in this domain to operate page objects in other domains or to enable js in other domains to operate page objects in this domain (between iframes). The following is a detailed explanation of the specific cross-domain situation:
URL Whether to allow communication
http://www.a.com/a.jshttp://www.a.com/b.js Same domain name Next, http://www.a.com/lab/a.js is allowed http://www.a.com/script/b.js Different folders under the same domain name are allowed http://www.a.com:8000/ a.js http://www.a.com/b.js The same domain name, different ports are not allowed http://www.a.com/a.js https://www.a.com/b.js The same domain name, Different protocols are not allowed http://www.a.com/a.jshttp://70.32.92.74/b.js The domain name and the corresponding ip of the domain name are not allowed http://www.a.com/a.jshttp:// script.a.com/b.js The main domain is the same, but the subdomain is different. Not allowed (cookies are not allowed to be accessed in this case) http://www.a.com/a.jshttp://a.com/b .js Same domain name, different second-level domain names (same as above) Not allowed (cookies are not allowed to be accessed in this case) http://www.cnblogs.com/a.jshttp://www.a.com/b.js Different domain names are not allowed
Two points need to be noted:
If there are cross-domain problems caused by protocols and ports, the "front desk" is powerless;
In cross-domain problems The problem is that domains are only identified by the "URL header" without trying to determine whether the same IP address corresponds to two domains or whether the two domains are on the same IP.
("URL header" refers to window.location.protocol window.location.host, which can also be understood as "Domains, protocols and ports must match".)
Same origin policy
The same domain name (or IP), the same port, and the same protocol are regarded as the same domain; scripts in a domain only have permissions within this domain. It can be understood that scripts in this domain can only read and write resources in this domain and cannot access other domains. H. This security restriction is called the same-origin policy.
The same origin policy is the most basic security function of the browser. Without a same-origin policy, ordinary users would have no security at all. All private information of users can be obtained by anyone, such as website cookies and email content. It is also vulnerable to CSRF attacks.
It should be noted that the domain name and the IP corresponding to the domain name are from different sources; if the main domain name is the same, the sub-domain names are also from different sources.
Cross-domain solution (summary)
1. document.domain cross-domain
As mentioned before, the browser has a same-origin policy, and one of its limitations is that it cannot request documents from different sources through the ajax method. The second limitation is that js cannot interact between frames in different domains in the browser.
Different frameworks can obtain window objects, but they cannot obtain the corresponding properties and methods.
For example, there is a page, its address is http://www.damonare.cn/a.html, there is an iframe in this page, its src is http://damonare.cn/b.html , Obviously, this page and the iframe inside it are in different domains, so we cannot get the things in the iframe by writing js code like this on the page:
<script type="text/javascript"> function test(){ var iframe = document.getElementById('ifame');
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>
At this time, document.domain This will come in handy. We only need to set the document.domain of the two pages http://www.damonare.cn/a.html and http://damonare.cn/b.html to the same domain name. That's it.
Note: The setting of document.domain is limited. We can only set document.domain to itself or a higher-level parent domain, and the main domain must be the same.
Set document.domain in the page http://www.damonare.cn/a.html:
<iframe id = "iframe" src="http://damonare.cn/b.html" onload = "test()"></iframe><script type="text/javascript"> document.domain = 'damonare.cn';//设置成主域 function test(){ //contentWindow 可取得子窗口的 window 对象 alert(document.getElementById('iframe').contentWindow); }</script>
Also set in the page http://damonare.cn/b.html document.domain:
The method of modifying document.domain is only applicable to the interaction between frames in different subdomains.
2. Cross-domain through location.hash
Because the parent window can read and write the URL of the iframe, and the iframe can also read and write the URL of the parent window, part of the URL is called hash, that is The # sign and the characters after it are generally used for browser anchor positioning. The server side does not care about this part. It should be said that the hash is not carried in the HTTP request process, so the modification of this part will not generate an HTTP request, but it will Generate browser history. The principle of this method is to change the hash part of the URL for two-way communication. Each window sends messages by changing the location of other windows (since the two pages are not under the same domain, IE and Chrome do not allow modification of the value of parent.location.hash, so a proxy iframe under the domain name of the parent window is required). And receive messages by listening for changes in your own URL. This method of communication will cause some unnecessary browser history records, and some browsers do not support the onhashchange event and need to poll to learn about URL changes. Finally, this method also has shortcomings, such as data being directly exposed in the URL. Data capacity and type are limited, etc.
Example:
If the parent page is baidu.com/a.html, and the page embedded in the iframe is google.com/b.html (the domain name and other url attributes are omitted here), to achieve this Communication between the two pages can be done through the following methods:
a.html transfers data to b.html
a.html and changes the src of the iframe to google.com/b.html#paco
b.html monitors the url change and triggers the corresponding operation
b.html transmits data to a.html. Since the two pages are not in the same domain, IE and Chrome do not allow modification of parent .location.hash value, so we need to create a hidden iframe under iframe
b.html with the help of a proxy under the domain name of the parent window. The src of this iframe is under the baidu.com domain, and hang it The hash data to be transmitted, such as src="http://www.baidu.com/proxy.html#data"
proxy.html listens to changes in the url and modifies the url of a.html (because a .html and *proxy.html are in the same domain, so proxy.html can modify the url hash of a.html)
a.html monitors changes in the url and triggers corresponding operations
b.html The key code of the page is as follows:
try { parent.location.hash = 'data'; } catch (e) { // ie、chrome的安全机制无法修改parent.location.hash, var ifrproxy = document.createElement('iframe'); ifrproxy.style.display = 'none'; ifrproxy.src = "http://www.baidu.com/proxy.html#data"; document.body.appendChild(ifrproxy); }
proxy.html The key code of the page is as follows:
/**
*Because parent.parent (i.e. baidu.com/a.html) and baidu.com/proxy.html belong to the same domain,
so the value of location.hash can be changed**/ parent.parent.location.hash = self.location.hash. substring(1);
3. Cross-domain through HTML5 postMessage method
Advanced browsers IE8, chrome, Firefox, Opera and Safari will all support this feature.
This function mainly includes the "message" event for receiving information and the "postMessage" method for sending messages.
For example, page A of the damonare.cn domain embeds a page B of the google.com domain through an iframe. Communication between A and B can be achieved through the following methods:
Page A sends messages through the postMessage method:
window.onload = function() { var ifr = document.getElementById('ifr'); var targetOrigin = "http://www.google.com"; ifr.contentWindow.postMessage('hello world!', targetOrigin); };
How to use postMessage: otherWindow.postMessage(message, targetOrigin);
otherWindow: refers to the target window, that is, which window to send the message to. It is a member of the window.frames property or is determined by the window. Window created by .open method.
message: is the message to be sent, the type is String, Object (not supported by IE8 and 9).
targetOrigin: is to limit the message receiving range, please use ' * ' if there is no limit.
Page B listens and accepts messages through the message event:
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 != 'undefined') { window.addEventListener('message', onmessage, false); } else if (typeof window.attachEvent != 'undefined') { //for ie window.attachEvent('onmessage', onmessage); }
Similarly, page B can also send messages, and then page A can listen and accept messages.
4. jsonp cross-domain
以上的这几种都是双向通信的,即两个iframe,页面与iframe,或是页面与页面之间的。
下面说几种单向跨域的(一般用来获取数据),因为通过script标签引入的js是不受同源策略的限制的。
所以我们可以通过script标签引入一个js或者是一个其他后缀形式(如php,jsp等)的文件,此文件返回一个js函数的调用。
比如,有个a.html页面,它里面的代码需要利用ajax获取一个不同域上的json数据,假设这个json数据地址是http://damonare.cn/data.php,那么a.html中的代码就可以这样:
可以看到获取数据的地址后面还有一个callback参数,按惯例是用这个参数名,但是你用其他的也一样。当然如果获取数据的jsonp地址页面不是你自己能控制的,就得按照提供数据的那一方的规定格式来操作了。
因为是当做一个js文件来引入的,所以http://damonare.cn/data.php返回的必须是一个能执行的js文件,所以这个页面的php代码可能是这样的(一定要和后端约定好哦):
$callback = $_GET['callback'];//得到回调函数名
$data = array('a','b','c');//要返回的数据
echo $callback.'('.json_encode($data).')';//输出?>
最终,输出结果为:dosomething([‘a’,’b’,’c’]);
如果你的页面使用jquery,那么通过它封装的方法就能很方便的来进行jsonp操作了:
<script type="text/javascript"> $.getJSON('http://example.com/data.php?callback=?,function(jsondata)'){ //处理获得的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'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:
在 iframe.html 中设置好了 window.name 为我们要传递的字符串。
我们在 index.html 中写了下面的代码:
var iframe = document.getElementById('iframe');var data = ''; iframe.onload = function() { data = iframe.contentWindow.name; };
报错!肯定的,因为两个页面不同源嘛,想要解决这个问题可以这样干:
var iframe = document.getElementById('iframe');var data = ''; iframe.onload = function() { iframe.onload = function(){ data = iframe.contentWindow.name; } iframe.src = 'about:blank'; };
或者将里面的 about:blank 替换成某个同源页面(about:blank,javascript: 和 data: 中的内容,继承了载入他们的页面的源。)
这种方法与 document.domain 方法相比,放宽了域名后缀要相同的限制,可以从任意页面获取 string 类型的数据。
本篇对跨域做出相应的总结,更多相关知识请关注php中文网。
相关推荐:
The above is the detailed content of Related knowledge points about front-end cross-domain summary. For more information, please follow other related articles on the PHP Chinese website!