Cet article fournit des explications pertinentes sur le cross-domain.
Avant-propos
La variété des solutions front-end inter-domaines est vraiment vertigineuse. Une fois, j'ai rencontré une scène d'entretien d'entreprise comme celle-ci. Plusieurs personnes attendaient l'entretien ensemble. Ils sont entrés un par un. L'intervieweur a demandé : « Parlez-moi d'une solution interdomaine. » et il l'a dit ((Trois types). dont je me souvenais à ce moment-là), puis l'intervieweur a dit : « Chacun de vous a dit ces trois-là quand vous êtes entré. A part ça, qu'y a-t-il d'autre ? .. Dans ce cas, je ne peux que résumer moi-même un blog afin de vérifier et combler les lacunes.
1. Qu'est-ce que le cross-domain ?
Le mot cross-domain signifie littéralement cross-domain, mais en fait, la portée de cross-domain n'est certainement pas si étroite. Le concept spécifique est le suivant : tant que le protocole, le nom de domaine et le port sont différents, ils sont considérés comme des domaines différents. La raison pour laquelle des problèmes inter-domaines surviennent est en fait facile à comprendre. Si des fichiers externes sont référencés de manière occasionnelle et que des pages sous différentes balises référencent des fichiers similaires les unes aux autres, le navigateur deviendra facilement confus et la sécurité ne sera pas garantie d'un coup. En tout, la sécurité passe avant tout. Cependant, en plus des restrictions de sécurité, cela pose également beaucoup de problèmes lors de l'injection d'applications iframe ou ajax. Par conséquent, nous devons utiliser certaines méthodes pour permettre à js dans ce domaine d'exploiter des objets de page dans d'autres domaines ou pour permettre à js dans d'autres domaines d'exploiter des objets de page dans ce domaine (entre les iframes). Ce qui suit est une explication détaillée de la situation spécifique entre les domaines : S'il faut autoriser la communication
http:// www.a.com/a.jshttp://www.a.com/b.js Le même nom de domaine Ensuite, autorisez http://www.a.com/lab/a.jshttp://www.a.com/script/b.js Différents dossiers sous le même nom de domaine autorisent http : //www.a.com:8000/ a.js http://www.a.com/b.js Le même nom de domaine, les ports différents ne sont pas autorisés http://www.a.com/a.js https ://www.a.com/b.js Le même nom de domaine, les différents protocoles ne sont pas autorisés http://www.a.com/a.jshttp://70.32.92.74/b.js Le nom de domaine et le Les adresses IP correspondantes du nom de domaine ne sont pas autorisées http://www.a.com/a.jshttp:// script.a.com/b.js Le domaine principal est le même, mais le sous-domaine est différent Non autorisé ( l'accès aux cookies n'est pas autorisé dans ce cas) http://www.a.com/a.jshttp://a.com/b .js Même nom de domaine, noms de domaine de deuxième niveau différents (comme ci-dessus) Non autorisé (l'accès aux cookies n'est pas autorisé dans ce cas) http://www.cnblogs.com/a.jshttp://www.a.com/b.js Différents noms de domaine ne sont pas autorisés
Il y a deux points à noter :
Si le problème inter-domaine est causé par le protocole et le port, la « réception » est impuissante
en cross-domain Le problème ; est que le domaine n'est identifié que par "l'entête URL" sans chercher à déterminer si la même adresse IP correspond à deux domaines ou si les deux domaines sont sur la même IP.
("En-tête d'URL" fait référence à window.location.protocol +window.location.host, qui peut également être compris comme "Les domaines, les protocoles et les ports doivent correspondre".)
Politique de même origine
Le même nom de domaine (ou IP), le même port et le même protocole sont considérés comme le même domaine ; les scripts d'un domaine n'ont des autorisations que dans ce domaine. lire et écrire les ressources de ce domaine, mais ne peut pas accéder aux autres ressources du domaine. Cette restriction de sécurité est appelée politique de même origine.
La politique de même origine est la fonctionnalité de sécurité la plus élémentaire du navigateur. Sans une politique de même origine, les utilisateurs ordinaires n’auraient aucune sécurité. Toutes les informations privées des utilisateurs peuvent être obtenues par n'importe qui, telles que les cookies du site Web et le contenu des e-mails. Il est également vulnérable aux attaques CSRF.
Il est à noter que le nom de domaine et l'IP correspondant au nom de domaine sont de sources différentes ; si le nom de domaine principal est le même, les noms de sous-domaines sont également de sources différentes.
Solution inter-domaines (résumé)
1. document.domain cross-domain
Comme mentionné précédemment, le navigateur a une politique de même origine, et l'une de ses limites est qu'il ne peut pas demander de documents provenant de sources différentes via la méthode ajax. La deuxième limitation est que js ne peut pas interagir entre les frames de différents domaines du navigateur.
Les objets Window peuvent être obtenus entre différents frameworks, mais les propriétés et méthodes correspondantes ne peuvent pas être obtenues.
Par exemple, il y a une page, son adresse est http://www.damonare.cn/a.html, il y a une iframe dans cette page, son src est http://damonare.cn/b.html , Évidemment, cette page et l'iframe qu'elle contient sont dans des domaines différents, nous ne pouvons donc pas obtenir les éléments dans l'iframe en écrivant du code js comme celui-ci sur la 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>
This When the time vient, document.domain peut être utile. Il suffit de définir le document.domain des deux pages http://www.damonare.cn/a.html et http://damonare.cn/b.html. remplacez-le par le même nom de domaine.
Remarque : le paramètre document.domain est limité. Nous ne pouvons définir document.domain que sur lui-même ou sur un domaine parent de niveau supérieur, et le domaine principal doit être le même.
Définissez document.domain dans la 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>
Dans la page http://damonare.cn/b.html Définissez également document.domain :
La méthode de modification de document.domain n'est applicable qu'à l'interaction entre les cadres de différents sous-domaines.
2. Interdomaine via location.hash
Parce que la fenêtre parent peut lire et écrire l'URL de l'iframe, et l'iframe peut également lire et écrire l'URL de la fenêtre parent. Une partie de l'URL est appelée hachage, c'est-à-dire que le signe # et les caractères qui le suivent sont généralement utilisés pour le positionnement de l'ancre du navigateur. Le côté serveur ne se soucie pas de cette partie. Il faut dire que le hachage n'est pas véhiculé dans la requête HTTP. processus, donc la modification de cette partie ne générera pas de requête HTTP, mais elle générera un historique du navigateur. Le principe de cette méthode est de modifier la partie hachage de l’URL pour une communication bidirectionnelle. Chaque fenêtre envoie des messages en changeant l'emplacement des autres fenêtres (comme les deux pages ne sont pas dans le même domaine, IE et Chrome n'autorisent pas la modification de la valeur de parent.location.hash, donc une iframe proxy sous le nom de domaine du la fenêtre parent est requise). Et recevez des messages en écoutant les modifications dans votre propre URL. Cette méthode de communication entraînera des enregistrements inutiles dans l'historique du navigateur, et certains navigateurs ne prennent pas en charge l'événement onhashchange et doivent interroger pour en savoir plus sur les modifications d'URL. Enfin, cette méthode présente également des inconvénients, tels que les données étant directement exposées dans les données de l'URL. la capacité et le type sont limités, etc.
Exemple :
Supposons que la page parent soit baidu.com/a.html et que la page intégrée dans l'iframe soit google.com/b.html (le nom de domaine et les autres attributs d'URL sont omis ici ), pour y parvenir, la communication entre les deux pages peut se faire par les méthodes suivantes :
a.html transfère les données vers b.html
a.html et change le src de l'iframe en google.com/b.html#paco
b.html détecte les changements dans l'url et déclenche les opérations correspondantes
b.html transmet les données à a.html puisque les deux pages ne sont pas dans. le même domaine, IE et Chrome n'autorisent pas la modification de la valeur .location.hash parent, nous devons donc utiliser une iframe proxy sous le nom de domaine de la fenêtre parent pour créer une iframe cachée sous
b.html. Le src de cette iframe est sous le domaine baidu.com, et accrochez-le. Les données de hachage à transmettre, telles que src="http://www.baidu.com/proxy.html#data"
proxy .html surveille le changement d'URL et modifie l'URL de a.html (car un .html et *proxy.html sont dans le même domaine, donc proxy.html peut modifier le hachage d'URL de a.html)
a.html écoute les changements dans l'url et déclenche les opérations correspondantes
b.html Le code clé de la page est le suivant :
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); }
Le code clé de la page proxy.html est comme suit :
/**
*Parce que parent.parent (c'est-à-dire baidu.com/a.html) et baidu.com/proxy.html appartiennent au même domaine,
donc la valeur de son location.hash peut être modifiée**/ parent.parent.location.hash = self.location hash.substring(1);
3. via la méthode postMessage HTML5
Les navigateurs avancés IE8+, Chrome, Firefox, Opera et Safari prendront tous en charge cette fonctionnalité.
Cette fonction comprend principalement l'événement "message" pour recevoir des informations et la méthode "postMessage" pour envoyer des messages.
Par exemple, la page A du domaine damonare.cn intègre une page B du domaine google.com via une iframe. La communication entre A et B peut être réalisée par les méthodes suivantes :
La page A envoie messages via la méthode postMessage :
window.onload = function() { var ifr = document.getElementById('ifr'); var targetOrigin = "http://www.google.com"; ifr.contentWindow.postMessage('hello world!', targetOrigin); };
Comment utiliser postMessage : otherWindow.postMessage(message, targetOrigin);
otherWindow : fait référence à la fenêtre cible, c'est-à-dire à quelle fenêtre envoyer le message et est membre de la propriété window.frames ou de la fenêtre créée par la méthode window.open.
message : est le message à envoyer, le type est String, Object (non pris en charge par IE8 et 9).
targetOrigin : consiste à limiter la plage de réception des messages. Veuillez utiliser ' * ' s'il n'y a pas de limite.
La page B écoute et reçoit des messages via l'événement de message :
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); }
De même, la page B peut également envoyer des messages, puis la page A peut écouter et recevoir des messages.
4. jsonp inter-domaines
以上的这几种都是双向通信的,即两个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中文网。
相关推荐:
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!