Maison  >  Article  >  interface Web  >  Méthodes inter-domaines en js

Méthodes inter-domaines en js

小云云
小云云original
2017-12-09 16:58:241450parcourir

Lors de la création d'un lecteur de musique oneday, je dois utiliser ajax pour envoyer une requête à l'API de Baidu Music, puis XMLHttpRequest ne peut pas charger 'http://....' Non 'Access-Control-. Autoriser' apparaît. L'en-tête -Origin' est présent sur la ressource de requête. L'origine 'http://....' n'est donc pas autorisée à accéder. Après la recherche, il a été constaté qu'il s'agissait d'un problème inter-domaines causé par le même. politique d'origine, alors renseignez-vous sur les points de connaissances inter-domaines.

Politique de même origine

La politique de même origine empêche les documents ou les scripts chargés à partir d'une source d'interagir avec des documents ou des scripts provenant d'une autre méthode. est un mécanisme de sécurité important pour isoler les fichiers potentiellement malveillants.

Lorsque deux pages ont le même protocole, port (si précisé) et nom de domaine, on peut dire que les deux pages sont de même origine.

Le tableau suivant est relatif à <code><span style="font-size: 14px;">http://store.company.com/dir/page.html</span>http://store.company.com/dir/page.htmlExemple de détection de même origine :

url 结果 原因
<span style="font-size: 14px;">http://store.company.com/dir2/other.html</span> 成功
<span style="font-size: 14px;">http://store.company.com/dir/inner/other.html</span> 成功
<span style="font-size: 14px;">https://store.company.com/secure.html</span> 失败 不同协议(<span style="font-size: 14px;">https</span><span style="font-size: 14px;">http</span>
<span style="font-size: 14px;">http://store.company.com:81/dir/etc.html</span> 失败 不同端口(81和80)
<span style="font-size: 14px;">http://news.company.com/dir/other.html</span> 失败 不同域名(<span style="font-size: 14px;">news</span><span style="font-size: 14px;">store</span>
url Résultat Raison
http://store.company .com/dir2/other.html Succès
http://store.company.com/dir/inner/other.html Succès
https://store.company.com/secure.html Échec Différents protocoles (https et http code>)
http://store.company.com:81/dir/etc.html Échec Différents ports (81 et 80)
http://news.company.com/dir/other.html Échec Différents noms de domaine (news et store)

S'il n'est pas de la même origine, trois comportements seront restreints :

  • Cookie, LocalStorage et IndexDB ne peuvent pas être lus

  • Le DOM ne peut pas être obtenu

  • La requête AJAX ne peut pas être envoyée

Éviter la politique de même origine (interdomaine)

Cookie

<span style="font-size: 14px;">document.domain</span>

Le cookie est un petit élément d'information écrit par le serveur sur le navigateur, qui ne peut être partagé que par les pages Web du même hôpital. Cependant, les noms de domaine de premier niveau des deux pages Web sont les mêmes, mais les noms de domaine de deuxième niveau sont différents. Le navigateur permet le partage de cookies via <code><span style="font-size: 14px;">document.domain</span>document.domaincode>

Par exemple, supposons qu'un script dans le document soit exécuté sur <code><span style="font-size: 14px;">http://store.company.com/dir/page.html</span><span style="font-size: 14px;">http://store.company.com/dir/ page.html</span>

La déclaration suivante :
<span style="font-size: 14px;">document.domain = "company.com"<br></span>

<span style="font-size: 14px;">http://news.company.com/dir/other.html</span>À l'heure actuelle, http://news .company.com/dir/other.html<span style="font-size: 14px;">http://store.company.com/dir/other.html</span>
et http://store.company.com/dir/other.html<span style="font-size: 14px;">document.cookie</span> code> peut être transmis

document.cookie pour définir ou obtenir des cookies, c'est-à-dire des cookies partagés.

Cependant, cette méthode convient aux fenêtres Cookie et iframe. LocalStorage et IndexDB ne peuvent pas contourner la même politique d'origine via cette méthode.

iframe<span style="font-size: 14px;">iframe</span><span style="font-size: 14px;">window.open</span>Si deux pages Web ont des sources différentes, elles ne peuvent pas obtenir le DOM de l'autre. Un exemple typique est . La fenêtre iframe

et la fenêtre ouverte par la méthode window.open<code><span style="font-size: 14px;">document.domain</span>, si la source est différente de la fenêtre parent, une erreur sera signalée.

À ce stade, si les noms de domaine de premier niveau des deux fenêtres sont les mêmes mais que seuls les noms de domaine de deuxième niveau sont différents, alors définissez document.domain

    peut contourner la politique de même origine.
  • Pour les sites Web d'origines complètement différentes, il existe actuellement trois méthodes pour résoudre le problème de communication entre les fenêtres inter-domaines.

  • identifiant du fragment

  • window.name

API de messagerie inter-documents (messagerie inter-documents)

<span style="font-size: 14px;">http://store.company.com/dir/other.html#fragment</span>Identifiant de fragment<span style="font-size: 14px;">#fragment</span>L'identifiant du fragment fait référence à la partie après # dans l'URL, c'est-à-dire

<p>http://store.company.com/dir/other.html# fragment<span style="font-size: 14px;"></span></p> de <span style="font-size: 14px;">hashchange</span><span style="font-size: 14px;">#fragment</span>(location.hash), si seul l'identifiant du fragment est modifié, la page ne sera pas réinitialisée et actualisée.

La fenêtre parent peut écrire des informations dans l'identifiant de fragment de la fenêtre enfant, et la fenêtre enfant écoute

<span style="font-size: 14px;">hashchange</span> <span style="font-size: 14px;">window.name</span> Les événements sont notifiés.

window.name

Chaque iframe a une fenêtre qui l'enveloppe. Cette fenêtre est une fenêtre enfant de la fenêtre supérieure, donc naturellement là. L'attribut window.name fait référence au nom de la fenêtre actuelle. La plus grande caractéristique de cet attribut est qu'elle ait ou non la même source. ou non, tant qu'elle se trouve dans la même fenêtre, toutes les pages de la fenêtre ont des autorisations de lecture et d'écriture pour window.name. La valeur de window.name ne peut être que sous la forme d'une chaîne. La capacité maximale de cette chaîne peut être d'environ 2 Mo ou même plus, selon les différents navigateurs.

例如,想要在<span style="font-size: 14px;">http://example/a.html</span>中获取<span style="font-size: 14px;">http://company.com/data.html</span>中的数据,可以在a.html中使用一个隐藏的iframe,将iframe的src首先设置为<span style="font-size: 14px;">http://company.com/data.html</span>,将其window.name设置为所需的数据内容,随后再将这个iframe的src设置为跟a.html页面同一个域的一个页面,不然a.html获取不到该iframe的window.name

<span style="font-size: 14px;">window.postMessage</span>

这是html5中新引入的一个API,可以使用它向其它的window对象发送消息,无论这个window对象属于同源还是不同源。

例如,父窗口<span style="font-size: 14px;">http://example/a.html</span>向子窗口<span style="font-size: 14px;">http://company.com/data.html</span>发送消息:

<span style="font-size: 14px;">var newWin = window.open('http://company.com/data.html', 'title')<br>newWin.postMessage('Hello World!'. 'http://company.com/data.html')<br></span>

<span style="font-size: 14px;">window.postMessage</span>方法的第一个参数是具体的信息内容,第二个参数是接收消息的窗口的源,即<span style="font-size: 14px;">协议</span>+<span style="font-size: 14px;">端口</span>+<span style="font-size: 14px;">域名</span>,也可以设置为<span style="font-size: 14px;">*</span>,表示不限制域名。

子窗口向父窗口发送消息的写法类似:

<span style="font-size: 14px;">window.opener.postMessage('Nice to see you', 'http://example/a.html')<br></span>

子窗口和父窗口都可以通过<span style="font-size: 14px;">message</span>时间,监听对方的消息。

<span style="font-size: 14px;">window.addEventListener('message', function(e) {<br>    // ...<br>}, false)<br></span>

<span style="font-size: 14px;">message</span>事件的事件对象<span style="font-size: 14px;">event</span>有以下三个属性:

  • event.source: 发送消息的窗口

  • event.origin: 消息发向的网址(可以限制目标网址)

  • event.data: 消息内容

通过<span style="font-size: 14px;">window.postMessage</span>,也可以读写其他窗口的<span style="font-size: 14px;">localStorage</span>

AJAX

同源策略规定,AJAX请求只能发给同源的网址,否则就报错,但是有三种方法可以规避这个限定:

  • JSONP

  • WebSocket

  • CORS

JSONP

JSONP是服务器与客户端跨源通信的常用方法。基本思想是利用<span style="font-size: 14px;"><script></span>请求脚本能够跨域访问的特性,先定义了一个回调方法,然后将其作为url参数的一部分发送到服务端,服务端通过字符串拼接的方式将数据包裹在回调方法中,再返回回来。

<span style="font-size: 14px;">// 网页动态插入`<script>`元素<br>function addScriptTag(src) {<br>    var script = document.createElement("script")<br>    script.setAttribute("type", "text/javascript")<br>    srcipt.src = src<br>    document.body.appendChild(script)<br>}<br><br>window.onload = function() {<br>    addScriptTag('http://example.com/ip?callback=foo')<br>}<br><br>function foo(data) {<br>    // ...<br>}<br></span>

WebSocket

WebSocket是一种通信协议,使用<span style="font-size: 14px;">ws://</span>(非加密)和<span style="font-size: 14px;">wss://</span>(加密)作为协议前缀。该协议不实行同源政策,只要服务支持,就可以通过它进行跨源通信。

浏览器发出的WebSocket请求的头信息中含有<span style="font-size: 14px;">Origin</span>字段,表示该请求的请求源,即发自哪个域名。(加入白名单)

CORS

跨域资源共享(Cross-Origin Resource Sharing,CORS)是一种使用额外的HTTP头来使一个用户代理从一个不同于当前站点(域)的服务器获取指定的资源的机制。用户代理使用跨域HTTP请求来获取与当前文档不同域、不用协议或端口的资源。

出于安全考虑,浏览器会限制从脚本内发起的跨域HTTP请求。而跨域资源共享(CORS)机制允许web应用服务器进行跨域访问控制,从而使跨域数据传输得以安全进行。浏览器支持在API容器中(例如<span style="font-size: 14px;">XMLHttpRequest</span><span style="font-size: 14px;">Fetch</span>)使用CORS,以降低跨域HTTP请求所带来的风险。

跨域资源共享标准允许在下列场景中使用跨域HTTP请求:

  • 由XMLHttpRequest或Fetch发起的跨域HTTP请求;

  • web字体(CSS中通过<span style="font-size: 14px;">@font-face</span>使用跨域字体资源),因此,网站就可以发布TrueType字体资源,并只允许已授权网站进行跨站调用;

  • WebGL贴图;

  • 使用drawImage将Images/video画面绘制到canvas;

  • 样式表(使用CSSOM);

  • Scripts(未处理的异常)。

浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)

只要同时满足以下两大条件,就属于简单请求:

1 请求方法是以下三种方法之一:

<span style="font-size: 14px;">- HEAD<br>- GET<br>- POST<br></span>

2 HTTP的头信息不超出以下几种字段:

<span style="font-size: 14px;">- Accept<br>- Accept-Language<br>- Content-Language<br>- Last-Event-ID<br>- Content-Type:(只限三个值:application/x-www-form-urlencoded、multipart/from-data、text/plain)<br></span>

只要不同时满足上面两个条件,就属于非简单请求

简单请求

对于简单请求,浏览器会在请求头部增加一个<span style="font-size: 14px;">Origin</span>字段。这个字段用来说明本次请求来自哪个源(协议+域名+端口)。服务器根据这个值决定是否同意这次请求。

如果<span style="font-size: 14px;">Origin</span>指定的源不在许可范围内,服务器会返回一个正常的HTTP回应。而这个回应的头信息不包含<span style="font-size: 14px;">Access-Control-Allow-Origin</span>字段,从而会抛出错误被<span style="font-size: 14px;">XMLHttpRequest</span><span style="font-size: 14px;">onerror</span>函数捕获,(回应的状态码有可能是200)。

如果<span style="font-size: 14px;">Origin</span>指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段

<span style="font-size: 14px;">Access-Control-Allow-Origin: ...<br>Access-Control-Allow-Credentials: true<br>Access-Control-Expose-Headers: callback<br>Content-Type: text/html; charset=utf-8<br></span>
  • <span style="font-size: 14px;">Access-Control-Allow-Origin</span>: 必须。值要么是请求时<span style="font-size: 14px;">Origin</span>的值,要么是'*'

  • <span style="font-size: 14px;">Access-Control-Allow-Credentials</span>: 可选。布尔值,决定是否允许发送Cookie,不需要则删除该字段。

  • <span style="font-size: 14px;">Access-Control-Expose-Headers</span>: 可选。CORS请求时,<span style="font-size: 14px;">XMLHttpRequest</span>对象的 <span style="font-size: 14px;">getResponseHeader()</span>方法只能拿到6个基本字段:<span style="font-size: 14px;">Cache-Control</span><span style="font-size: 14px;">Content-Language</span><span style="font-size: 14px;">Content-Type</span><span style="font-size: 14px;">Expires</span><span style="font-size: 14px;">Last-Modified</span><span style="font-size: 14px;">Pragma</span>。如果想拿到其他字段,就需要在<span style="font-size: 14px;">Access-Control-Expose-Header</span>里面指定。上面的例子指定为callback,则可以使用<span style="font-size: 14px;">getResponseHeader(callback)</span>获取callback字段的值。

CORS请求默认不发送Cookie和HTTP认证信息。如果要把Cookie发送到服务器,一方面要服务器同意,指定<span style="font-size: 14px;">Access-Control-Allow-Credentials</span>字段,另一方面,开发者需要在AJAX请求中设置<span style="font-size: 14px;">withCredentials</span>属性:

<span style="font-size: 14px;">var xhr = new XMLHttpRequest()<br>xhr.withCredentials = true<br></span>

否则,即使服务器同意发送Cookie,浏览器也不会发送。

需要注意的是,如果要发送Cookie,<span style="font-size: 14px;">Access-Control-Allow-Origin</span>就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie依然遵循同源策略,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且跨域的原网页中的<span style="font-size: 14px;">document.cookie</span>操作也无法获取嗷服务器域名下的Cookie。

非简单请求

非简单请求是那种对服务器有特殊要求的请求,比如请求方法是<span style="font-size: 14px;">PUT</span><span style="font-size: 14px;">DELETE</span>,或者<span style="font-size: 14px;">Content-Type</span>字段的类型是<span style="font-size: 14px;">application/json</span>

非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为“预检”请求。

浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP操作和头信息字段。只有得到肯定答复,浏览器才会发出正式的<span style="font-size: 14px;">XMLHttpRequest</span>请求,否则就报错。

“预检”请求用请求方法是<span style="font-size: 14px;">OPTIONS</span>,表示这个请求是用来询问的。头信息里面,关键字段是<span style="font-size: 14px;">Origin</span>,表示请求来自哪个源。

还有以下两个特殊字段:

  • <span style="font-size: 14px;">Access-Control-Request-Method</span>: 必须。列出非简单请求的请求类型

  • <span style="font-size: 14px;">Access-Control-Request-Headers</span>: 非简单请求额外携带的头信息字段。

服务器返回的响应:

<span style="font-size: 14px;">Access-Control-Allow-Methods: ...<br>Access-Control-Expose-Headers: callback<br>Access-Control-Allow-Credentials: true<br>Access-Control-Max-Age: 1728000<br></span>
  • Access-Control-Allow-Methods: 必须。逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。为了避免多次“预检”行为。

  • Access-Control-Expose-Headers : Si la requête du navigateur inclut <span style="font-size: 14px;">Access-Control-Request-Headers</span>Access-Control-Request-Headers, le champ <span style="font-size: 14px;">Access-Control-Allow-Headers</span><span style="font-size: 14px;">Access-Control-Allow-Headers</span>

    est obligatoire. Il s'agit également d'une chaîne séparée par des virgules indiquant tous les champs d'en-tête pris en charge par le serveur, sans se limiter aux champs demandés par le navigateur en « contrôle en amont ».
  • Access-Control-Allow-Credentials : a la même signification qu'une simple demande.
  • Access-Control-Max-Age : La période de validité de cette demande de contrôle en amont.

Comparaison de CORS et JSONP

CORS a le même objectif que JSONP, mais est plus puissant que JSONP.

<span style="font-size: 14px;">GET</span>JSONP ne prend en charge que les requêtes GET

, CORS prend en charge tous les types de requêtes HTTP. L'avantage de JSONP est qu'il prend en charge les anciens navigateurs et peut demander des données à des sites Web qui ne prennent pas en charge CORS.

Recommandations associées :

Étapes pour implémenter le chargement différé et le cross-domain à l'aide de Js

Comment comprendre le cross-domain de Js

Explication détaillée de la façon d'activer la fonction cross-domain de Laravel

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!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn