この記事では、クロスドメインに関する関連説明を提供します。
はじめに
フロントエンドのクロスドメイン ソリューションの多様性には、本当に目まぐるしいものがあります。私はかつてこのような企業の面接場面に遭遇しました。数人が一緒に面接を待っていました。面接官は「クロスドメインのソリューションについて教えてください。」と尋ねました。(3 種類)そのとき頭の中に覚えていました)そして面接官はこう言いました、「あなたたちは入ってきたときにこの3つを言いました。これら以外に他に何がありますか?」そして、それは突然風の中で混乱しました。 .. この場合、空白を確認して埋めるためには、自分でブログを要約するしかありません。
1. クロスドメインとは何ですか?
クロスドメインという言葉は文字通りクロスドメイン名を意味しますが、実際にはクロスドメインの範囲は決して狭いものではありません。具体的な概念は次のとおりです。プロトコル、ドメイン名、ポートが異なれば、別のドメインとして扱われます。クロスドメインの問題が発生する理由は、実際には簡単に理解できます。外部ファイルが無造作に参照され、異なるタグの下にあるページが相互に類似したファイルを参照すると、ブラウザが混乱しやすくなり、セキュリティが保証されなくなります。何事においても安全が第一です。ただし、セキュリティ上の制限に加えて、iframe または ajax アプリケーションの挿入には多くの問題が発生します。したがって、いくつかのメソッドを使用して、このドメインの js が他のドメインのページ オブジェクトを操作できるようにするか、他のドメインの js がこのドメイン (iframe 間) のページ オブジェクトを操作できるようにする必要があります。以下は、特定のクロスドメイン状況の詳細な説明です。通信を許可するかどうか
http://www.a.com/a.jshttp://www.a.com/b.js 同一ドメイン名 http :// は許可されます 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 同じメイン ドメイン、異なるサブドメイン 許可されません (この場合、Cookie へのアクセスは許可されません) http://www. a.com/a.jshttp://a.com/b.js 同じドメイン名、異なる第 2 レベル ドメイン名 (同上) 不可 (この場合、Cookie へのアクセスは許可されません) http:// www.cnblogs.com/a.jshttp://www.a.com/b.js 異なるドメイン名は許可されません
次の 2 つの点に注意する必要があります:
クロスドメインの問題がプロトコルによって引き起こされている場合と、
クロスドメインの問題の場合、同じ IP アドレスが 2 つのドメインに対応しているか、または 2 つのドメインが同じドメイン上にあるかどうかを判断することなく、ドメインは「URL ヘッダー」によってのみ識別されます。同じIP。
(「URL ヘッダー」は、window.location.protocol +window.location.host を指します。これは、「ドメイン、プロトコル、ポートが一致する必要がある」とも解釈できます。)
同一オリジン ポリシー
同じドメイン名 (または IP) )、同じポートとプロトコルは同じドメイン内にあるとみなされます。ドメイン内のスクリプトは、このドメイン内のリソースの読み取りと書き込みのみが可能ですが、リソースにはアクセスできないことがわかります。他のドメインでも。このセキュリティ制限は同一生成元ポリシーと呼ばれます。
同一生成元ポリシーは、ブラウザーの最も基本的なセキュリティ機能です。同一生成元ポリシーがなければ、通常のユーザーにはまったくセキュリティがありません。 Web サイトの Cookie や電子メールの内容など、ユーザーのすべての個人情報は誰でも取得できる可能性があります。 CSRF 攻撃に対しても脆弱です。
ドメイン名とそのドメイン名に対応する IP は異なるソースからのものであることに注意してください。メイン ドメイン名が同じ場合、サブドメイン名も異なるソースからのものです。
クロスドメイン ソリューション (概要)
1. document.domain クロスドメイン
前に述べたように、ブラウザには同一生成元ポリシーがあり、その制限の 1 つは、ajax メソッドを通じて異なるソースからドキュメントをリクエストできないことです。 2 番目の制限は、js がブラウザー内の異なるドメインのフレーム間で対話できないことです。
異なるフレームワーク間ではウィンドウオブジェクトは取得できますが、対応するプロパティやメソッドは取得できません。
たとえば、アドレスが 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('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>
このとき、 document.domain が役に立ちます。 http://www.damonare.cn/a.html と http://damonare.cn/b.html の 2 つのページの 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 = 'damonare.cn';//设置成主域 function test(){ //contentWindow 可取得子窗口的 window 对象 alert(document.getElementById('iframe').contentWindow); }</script>
ページ http://www.damonare.cn/a.html で、 document.domain:
< script type="text/javascript">
document も設定します。 domain = 'damonare.cn';//このページをiframeで読み込む際に、メインページの document.domain と同じになるように document.domain も設定します ドキュメントの修正方法。ドメインは、異なるサブドメイン内のフレーム間の対話にのみ適用されます。
親ページがbaidu.com/a.html、iframeに埋め込まれたページがgoogle.com/b.htmlの場合(ドメイン名やその他のURL属性はここでは省略します)、この2つの間の通信は次のメソッドを使用できます:
a.html データを b.html に転送し、iframe の src を google.com/b.html#paco に変更します
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 メソッドを通じてメッセージを送信します。
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); }
postMessageの使い方 :otherWindow.postMessage(message, targetOrigin);
otherWindow: ターゲットウィンドウ、つまりメッセージの送信先のウィンドウを指します。 window.frames プロパティのメンバーです。 window.open メソッドによって作成されたウィンドウ。
message: 送信されるメッセージです。タイプは String、Object (IE8 および 9 ではサポートされていません) です。
targetOrigin: メッセージの受信範囲を制限します。制限がない場合は ' * ' を使用してください。
ページ B は、メッセージ イベントを通じてメッセージをリッスンおよび受信します:
window.onload = function() { var ifr = document.getElementById('ifr'); var targetOrigin = "http://www.google.com"; ifr.contentWindow.postMessage('hello world!', targetOrigin); };
同様に、ページ 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中的代码就可以这样:
可以看到获取数据的地址后面还有一个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中文网。
相关推荐:
以上がフロントエンドのクロスドメインに関する関連知識ポイントの概要の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。