由于平安的缘由,浏览器做了许多方面的事情,由此也就引入了一系列的跨域题目,需要注重的是:
跨域并不是浏览器限定了提议跨站要求,而是跨站要求能够平常提议,然则返回效果被浏览器阻拦了。最好的例子是 crsf
跨站进击道理,要求是发送到了后端服务器不管是不是跨域!注重:有些浏览器不许可从HTTPS的域跨域接见HTTP,比方Chrome和Firefox,这些浏览器在要求还未发出的时刻就会阻拦要求,这是一个惯例
1. JSONP
JSONP
的全称是 “JSON With Padding”, 词面意义上明白就是 “添补式的JSON”。它不是一个新颖的东西,隶属于 JSON
的一种运用要领,或许说是一种运用形式,能够处置惩罚一些罕见的浏览器端网页跨域题目。
正如他的称号一样,它是指被包括在挪用函数中的JSON,比方如许:
callback({"Name": "小明", "Id" : 1823, "Rank": 7})
由于 jQuery
的一些缘由,使得 JSONP
经常与 Ajax
殽杂。实际上,他们没有任何关系。
由于浏览器的同源战略,使得在网页端涌现了这个“跨域”的题目,但是我们发明,一切的 src
属性并没有遭到相干的限定,比方 img
/ script
等。
JSONP
的道理就要从 script
提及。script
能够实行其他域的js
函数,比方如许:
a.html
...
<script>
function callback(data) {
console.log(data.url)
}
</script>
<script src='b.js'></script>
...
b.js
callback({url: 'http://www.rccoder.net'})
明显,上面的代码是能够实行的,而且能够在console内里输出http://www.rccoder.net
应用这一点,假如b.js内里的内容不是牢固的,而是依据一些东西自动天生的, 嗯,这就是JSONP的重要道理了。回调函数+数据就是 JSON With Padding
了,回调函数用来相应应该在页面中挪用的函数,数据则用来传入要实行的回调函数。
至于这个数据是怎样发生的,说粗暴点不过就是字符串拼接了。
简朴总结一下: Ajax 是应用 XMLHTTPRequest 来要求数据的,而它是不能要求差别域上的数据的。然则,在页面上援用差别域的 js 文件倒是没有任何题目标,如许,应用异步的加载,要求一个 js 文件,而这个文件的内容是动态天生的(背景言语字符串拼接出来的),内里包括的是 JSON With Padding(回调函数+数据),之前写的谁人函数就由于新加载进来的这段动态天生的 js 而实行,也就是猎取到了他要猎取的数据。
反复一下,在一个页面中,a.html如许写,获得 UserId 为 1823 的信息:
a.html
...
src="http://server2.example.com/RetrieveUser?UserId=1823&callback=parseResponse">
...
要求这个地点会获得一个能够实行的 JavaScript。比方会获得:
parseResponse({"Name": "小明", "Id" : 1823, "Rank": 7})
如许,a.html内里的 parseResponse()
这个函数就可以实行而且获得数据了。
等等,jQuery究竟做了什么:
jQuery 让 JSONP 的运用API和Ajax的如出一辙:
$.ajax({
method: 'jsonp',
url: 'http://server2.example.com/RetrieveUser?UserId=1823',
success: function(data) {
console.log(data)
}
})
之所以能够如许是由于 jQuery 在背地倾泻了心血,它会在实行的时刻天生函数替代callback=dosomthing
,然后猎取到数据以后销毁掉这个函数,起到一个暂时的代办器作用,如许就拿到了数据。
JSONP 的后话:
JSONP的这类完成体式格局不受同源战略的影响,兼容性也很好;然则它之支撑 GET 体式格局的清晰,只支撑 HTTP 要求这类特别的状况,关于两个差别域之间两个页面的相互挪用也是无计可施。
2. CORS
XMLHttpRequest
的同源战略看起来是云云的变态,即使是统一个公司的产物,也不可能完整在统一个域上面。还好,收集设想者在设想的时刻考略到了这一点,能够在服务器端举行一些定义,许可部份收集接见。
CORS 的全称是 Cross-Origin Resource Sharing,即跨域资源同享。他的道理就是运用自定义的 HTTP 头部,让服务器与浏览器举行沟通,重假如经由过程设置相应头的 Access-Control-Allow-Origin
来到达目标的。如许,XMLHttpRequest 就可以跨域了。
值得注重的是,平常状况下的 XMLHttpRequest 是只发送一次要求的,然则跨域题目下许多是会发送两次的要求(预发送)。
越发细致的内容能够拜见:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
CORS 的后话:
相比之下,CORS 就支撑一切范例的 HTTP 要求了,然则在兼容上面,每每一些老的浏览器并不支撑 CORS。
Desktop:
浏览器 | 版本 |
---|---|
Chrome | 4 |
Firefox (Gecko) | 3.5 |
Internet Explorer | 8 (via XDomainReques) 10 |
Opera | 12 |
Safari | 4 |
Mobile:
装备 | 版本 |
---|---|
Android | 2.1 |
Chrome for Android | yes |
Firefox Mobile (Gecko) | yes |
IE Mobile | ? |
Opera Mobile | 12 |
Safari Mobile | 3.2 |
3. window.name
window.name 在一个窗口(标签)的生命周期以内是同享的,应用这点就可以够传输一些数据。
除此之外,连系 iframe 还能完成越发壮大的功用:
需要3个文件: a/proxy/b
a.html
<script type="text/javascript">
var state = 0,
iframe = document.createElement('iframe'),
loadfn = function() {
if (state === 1) {
var data = iframe.contentWindow.name; // 读取数据
alert(data); //弹出'I was there!'
} else if (state === 0) {
state = 1;
iframe.contentWindow.location = "http://a.com/proxy.html"; // 设置的代办文件
}
};
iframe.src = 'http://b.com/b.html';
if (iframe.attachEvent) {
iframe.attachEvent('onload', loadfn);
} else {
iframe.onload = loadfn;
}
document.body.appendChild(iframe);
</script>
b.html
<script type="text/javascript">
window.name = 'I was there!'; // 这里是要传输的数据,大小平常为2M,IE和firefox下能够大至32M摆布
// 数据格式能够自定义,如json、字符串
</script>
proxy 是一个代办文件,空的就可以够,需要和 a 在统一域下
4. document.domain
在差别的子域 + iframe交互的时刻,猎取到别的一个 iframe 的 window对象是没有题目标,然则猎取到的这个window的要领和属性大多数都是不能运用的。
这类征象能够借助document.domain
来处置惩罚。
example.com
<iframe id='i' src="1.example.com" onload="do()"></iframe>
<script>
document.domain = 'example.com';
document.getElementById("i").contentWindow;
</script>
1.example.com
<script>
document.domain = 'example.com';
</script>
如许,就可以够处置惩罚题目了。值得注重的是:document.domain
的设置是有限定的,只能设置为页面本身或许更高一级的域名。
document.domain的后话:
应用这类要领是极为轻易的,然则假如一个网站被进击以后别的一个网站极可能会引起平安漏洞。
5.location.hash
这类要领能够把数据的变化显现在 url 的 hash 内里。然则由于 chrome 和 IE 不许可修正parent.location.hash 的值,所以需要再加一层。
a.html 和 b.html 举行数据交换。
a.html
function startRequest(){
var ifr = document.createElement('iframe');
ifr.style.display = 'none';
ifr.src = 'http://2.com/b.html#paramdo';
document.body.appendChild(ifr);
}
function checkHash() {
try {
var data = location.hash ? location.hash.substring(1) : '';
if (console.log) {
console.log('Now the data is '+data);
}
} catch(e) {};
}
setInterval(checkHash, 2000);
b.html
//模仿一个简朴的参数处置惩罚操纵
switch(location.hash){
case '#paramdo':
callBack();
break;
case '#paramset':
//do something……
break;
}
function callBack(){
try {
parent.location.hash = 'somedata';
} catch (e) {
// ie、chrome的平安机制没法修正parent.location.hash,
// 所以要应用一个中心域下的代办iframe
var ifrproxy = document.createElement('iframe');
ifrproxy.style.display = 'none';
ifrproxy.src = 'http://3.com/c.html#somedata'; // 注重该文件在"a.com"域下
document.body.appendChild(ifrproxy);
}
}
c.html
//由于parent.parent和本身属于统一个域,所以能够转变其location.hash的值
parent.parent.location.hash = self.location.hash.substring(1);
如许,应用中心的 c 层就可以够用 hash 到达 a 与 b 的交互了。
6.window.postMessage()
这个要领是 HTML5 的一个新特征,能够用来向其他一切的window对象发送音讯。需要注重的是我们必需要保证一切的剧本实行完才发送MessageEvent,假如在函数实行的过程当中挪用了他,就会让背面的函数超时没法实行。
https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
参考资料
http://www.cnblogs.com/rainman/archive/2011/02/20/1959325.html
http://www.cnblogs.com/rainman/archive/2011/02/21/1960044.html
硬广
原文地点: https://github.com/rccoder/blog/issues/5
迎接 star 堆栈~