クロスドメインとは何ですか?
a.com/get.html が b.com/data.html のデータを取得する必要があり、a.com と b.com が同じサーバーではないとします。これは Javascript を伴うクロスドメインです。同一オリジンポリシーとは、簡単に言えば、Web サイトのセキュリティを保護し、外部ドメイン (非同一オリジン) サーバーからの js によって Web サイトのコンテンツが変更されるのを防ぐことです。
表を引用して、相互原因を引き起こす条件を確認してください:
しかし、場合によってはこれを本当に行う必要があるので、どのような方法があるでしょうか?
1.JsonP
クロスドメインに関して言えば、まず jsonp について触れずにはいられません。 jsonp は実際には JavacScript Object Notation with Padding の略称で、コンテンツが詰め込まれた json 形式のデータとして理解できます。
コールバックが上記で宣言されており、外部ドメイン b.com の data.js が呼び出され、data.js が呼び出されるため:
callback({msg:"tqtan"});
このように、外部ドメインを参照するjsを呼び出すと、ローカルのcallback()が呼び出され、データ送信が実現されます。
上記は単純なクロスドメインです。jQuery の実際のアプリケーションを見てみましょう。
jQuery の Ajax は、次の 2 つの方法で外部ドメインからデータを取得できます。
1. $.getJSON()
このメソッドは単純かつ粗雑で、外部ドメインから Json をリクエストします。
上記のリクエストが b.com のサーブレット ページにアクセスし、渡されたパラメーターが callback=? であるとすると、jQuery はプレースホルダー? に埋める文字列を自動的に生成します (例: callback=jQuery17207481773362960666_1332575486681)。これにより、サーバーで一意の識別子が宣言されます。サーバーは、このコールバック値を含む json 形式のデータを返すだけで済みます。例:
このようにして、同じオリジン以外のサーバーからデータを正常に取得できます。
2. $.ajax()
実装原理は上記と同じですが、より多くのリンクをカスタマイズできる点が異なります。
$.ajax({ url:'http://b.com/dataServlet?words=hi', dataType:'jsonp', jsonp : 'jsoncallback', jsoncallback : 'tqtan', success:function(data){ console.log(data.msg); }, error: function (e) { console.log(e); } });
コールバックの名前はカスタマイズできます。ここでは「tqtan」に変更され、値 Words=hi を渡すことができます。
JsonP 形式は GET 形式でのみサーバーにリクエストできることに注意してください。
2. ドキュメント.ドメイン
この方法は、メイン ドメインが同じでサブドメインが異なるクロスドメインにのみ適用されます。
これは get.a.com と data.a.com の間のクロスドメインの問題です。解決策は非常に簡単です。
get.a.com/get.html が data.a.com/data.html のデータを取得する必要がある場合は、まず get.html に iframe を挿入し、src が data.a.com/data.html を指すようにしてから、 data.html に document.domain='a.com' と記述して、data.html のコンテンツを制御します。
//get.html var iframe = document.creatElement("iframe"); iframe.src="http://data.a.com/data.html"; iframe.style.display="none"; document.body.appendChild(iframe); document.domain = 'a.com'; iframe.onload = function(){ var otherDocument = iframe.contentDocument || iframe.contentWindow.document; //otherDocument就是另一个页面的document //do whatever you want.. }; //data.html document.domain = 'a.com';
3. URL ハッシュ
URL ハッシュを通じてクロスドメインを実現することもできます。ハッシュは、http://targetkiller.net/index.html#data など、url# の後のコンテンツです。#data はハッシュです。これを使用してクロスドメインを実現するにはどうすればよいですか?
同じ例ですが、a.com/get.html は b.com/data.html を取得する必要があります。まず get.html で iframe を作成し、src は引き続き data.html を指し、次にハッシュ値をパラメータを渡します。相手側の Data.html は、取得したハッシュに基づいて応答し、iframe 自体を作成し、src が a.com/proxy.html を指し、応答データをハッシュに追加します。その後、a.com/proxy.html は、同じ a.com 親ドメイン内の get.html のハッシュを変更するだけで済みます。最後に、データを取得するにはどうすればよいでしょうか? get.html にタイマー setInterval を記述し、新しいハッシュがあるかどうかを定期的に監視するだけです。
これを見て、あなたは混乱するかもしれません。ここでいくつかの質問があります:
1.proxy.html の役割は何ですか?
get.html と data.html は同じドメインにないため、location.hash 値は変更できません。そのため、proxy.html を使用して、最初にページにジャンプしてプロキシを見つけてから、parent.location.hash を使用します。つまり、息子 (get.html) も応答を取得できるように父親を変更します。
a.com/get.html
var iframe = document.createElement('iframe'); iframe.src = 'http://a.com/get.html#data'; iframe.style.display = 'none'; document.body.appendChild(iframe); //周期检测hash更新 function getHash() { var data = location.hash ? location.hash.substring(1) : ''; console.log(data); } var hashInt = setInterval(function(){getHash()}, 1000); a.com/proxy.html parent.location.hash = self.location.hash.substring(1); b.com/data.html //模拟一个简单的参数处理操作 if(location.hash){ var data = location.hash; doSth(data); } function doSth(data){ console.log("from a.com:"+data); var msg = "hello i am b.com"; var iframe = document.createElement('iframe'); iframe.src = "http://a.com/proxy.html#"+msg; iframe.style.display = 'none'; document.body.appendChild(iframe); }
4、window.name
这种方法比较巧妙,引用圆心的解释,name 值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)。
具体例子依旧如上,同时也是需要一个代理页面。
a.com/get.html请求b.com/data.html,首先get.html创建一个iframe,src指向data.html,然后监听iframe的onload事件。与此同时,在data.html设置window.name = data;把window.name赋值。然后onload事件后马上把iframe的跳到本地a.com/proxy.html。因此window.name就共享到了src为proxy.html的找个iframe中,接下来,就是同源间获取值的事了。
a.com/get.html
var state = 0, iframe = document.createElement('iframe'), iframe.src = 'http://b.com/data.html"; iframe.style.display = 'none'; loadfn = function() { if (state === 1) { var data = iframe.contentWindow.name; console.log(data); } else if (state === 0) { state = 1; //跳到proxy.html iframe.contentWindow.location = "http://a.com/proxy.html"; } }; if (iframe.attachEvent) { iframe.attachEvent('onload', loadfn); } else { iframe.onload = loadfn; } document.body.appendChild(iframe); a.com/proxy.html // proxy.html的操作主要是删除get.html的iframe,避免安全问题发生 iframe.contentWindow.document.write(''); iframe.contentWindow.close(); document.body.removeChild(iframe); b.com/data.html var data = "hello,tqtan"; window.name = data;
5、 postMessage()
html5的新方法postMessage()优雅地解决了跨域,也十分容易理解。
发送方调用postMessage()内容,接受方监听onmessage接受内容即可。
假设发送方为a.com/send.html,接受方为b.com/receive.html。
a.com/send.html
var iframe = document.createElement("iframe"); iframe.src = "http://b.com/receive.html"; document.body.appendChild(iframe); iframe.contentWindow.postMessage("hello","http://b.com"); b.com/receive.html window.addEventListener('message', function(event){ // 通过origin属性判断消息来源地址 if (event.origin == 'http://a.com') { console.log(event.data); console.log(event.source);//发送源的window值 } }, false);
6、CORS(后台实现)
以上5点都是前端实现的跨域,但是后台参与会让跨域更容易解决,也就是用CORS。
CORS是Cross-Origin Resource Sharing的简称,也就是跨域资源共享。它有多牛逼?之前说JsonP只能get请求,但CORS则可以接受所有类型的http请求,然而CORS只有现代浏览器才支持。
怎样使用?前端只需要发普通ajax请求,注意检测CORS的支持度。引用自蒋宇捷。
function createCORSRequest(method, url) { var xhr = new XMLHttpRequest(); if ("withCredentials" in xhr) { // 此时即支持CORS的情况 // 检查XMLHttpRequest对象是否有“withCredentials”属性 // “withCredentials”仅存在于XMLHTTPRequest2对象里 xhr.open(method, url, true); } else if (typeof!= "undefined") { // 否则检查是否支持XDomainRequest,IE8和IE9支持 // XDomainRequest仅存在于IE中,是IE用于支持CORS请求的方式 xhr = new XDomainRequest(); xhr.open(method, url); } else { // 否则,浏览器不支持CORS xhr = null; } return xhr; } var xhr = createCORSRequest('GET', url); if (!xhr) { throw new Error('CORS not supported'); }
与此同时,服务器端只需要设置Access-Control-Allow-Origin头即可。
java中你只需要设置
为了安全,也可以将*改为特定域名,例如a.com。