Home >Web Front-end >JS Tutorial >In-depth analysis of Javascript cross-domain issues_javascript skills
What is cross-domain?
Suppose a.com/get.html needs to obtain the data in b.com/data.html, and a.com and b.com are not the same server. This is cross-domain cross-domain involving Javascript. The same-origin policy, simply put, is to protect the security of the website and prevent the content of the website from being modified by js from external domain (non-same-origin) servers.
Quote a table to see what are the conditions that cause cross-causes:
But sometimes we really need to do this, so what methods do we have?
1. JsonP
When it comes to cross-domain, we cannot fail to mention jsonp first. jsonp is actually the abbreviation of JavacScript Object Notation with Padding, which can be understood as json format data filled with content.
Because the callback is declared above and the data.js of the external domain b.com is called, and the data.js is called:
callback({msg:"tqtan"});
In this way, when calling js that refers to the external domain, the local callback() will be called to achieve data transmission.
The above is just a simple cross-domain, let's look at the real application of jQuery.
Ajax in jQuery can pull data from external domains through two methods:
1. $.getJSON()
This method is simple and crude, requesting Json from the external domain.
Assume that the above request accesses the servlet page under b.com, and the passed parameter is callback=?, jQuery will automatically generate a string to fill in the placeholder?, for example, callback=jQuery17207481773362960666_1332575486681. This declares a unique identifier with the server. The server only needs to return json format data with this callback value, for example:
In this way, you can successfully obtain data from non-same origin servers.
2. $.ajax()
The implementation principle is the same as above, except that more links can be customized.
$.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); } });
The name of the callback can be customized, here it is changed to 'tqtan', and the value words=hi can be passed here.
Note that JsonP format can only be requested to the server in GET format.
2. document.domain
This method only applies to cross-domains where the main domain is the same but the subdomains are different.
That is the cross-domain problem between get.a.com and data.a.com. The solution is very simple:
If get.a.com/get.html needs to obtain the data of data.a.com/data.html, first insert an iframe in get.html, src points to data.a.com/data.html, and then in data.html Write document.domain='a.com'; to control the content in 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 hash
You can also achieve cross-domain through URL hash. Hash is the content after url#, such as http://targetkiller.net/index.html#data, where #data is the hash. How to use this to achieve cross-domain?
Still the same example, a.com/get.html needs to get b.com/data.html, first create an iframe in get.html, src still points to data.html, and then add the hash value to pass the parameters. Data.html on the other end responds based on the obtained hash, creates an iframe itself, src points to a.com/proxy.html, and adds the response data to the hash. After that, a.com/proxy.html only needs to modify the hash of get.html in the same a.com parent domain. Finally, how to obtain the data? You only need to write a timer setInterval in get.html and monitor whether there are new hashes regularly.
Seeing this, you may feel confused. Here are a few questions:
1.What is the role of proxy.html?
Since get.html and data.html are not in the same domain, the location.hash value cannot be modified, so using proxy.html, first jump to the page to find a proxy, and then use parent.location.hash, that is, modify the father to let the son (get.html) also gets a response.
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。