跨域:浏览器对于javascript的同源策略的限制,例如a.com下面的js不能调用b.com中的js,对象或数据(因为a.com和b.com是不同域),所以跨域就出现了。
同源策略:浏览器施加的安全限制,请求的url地址,必须与浏览器上的url地址处于同域上,也就是协议,域名和端口都相同。



需要注意的是:对于当前页面来说页面存放的JS文件的域不重要,重要的是加载该JS页面所在什么域
那么下面我们开始探讨跨域的一些方式以及原理
1.JSONP
首先我们需要知道的是 HTML 中 script 标签可以加载其他域下的js,比如我们经常引入一个其他域下线上cdn的jQuery。
因此 可以利用这个特性实现从其他域下获取数据。
<script src="http://api.data.com/getInfo.php"></script>
这里我们会有一个疑问:我们向其他域数据接口发送请求,获取数据后作为 js 来执行,但是这里的数据是 JSON 格式的数据,如果直接作为 js 运行的话我们应该如何去得到这个数据,进而进行我们想要的操作呢?
<script src="http://api.data.com/getInfo.php?callback=showData"></script>
这个请求到达后端后,后端会去解析callback这个参数获取到字符串showData,在发送数据时做如下的处理:
之前后端返回的数据是:{ "info": "something" }
,现在返回的数据是:showData({ "info": "something" })
,前端script标签在加载数据后会把 「 showData({ "info": "something" }) 」当作js来执行,实际上就是调用了showData函数,此时参数是 { "info": "something" }。用户只需要提前在页面定义好showData这个全局函数,在函数内部处理参数即可。
<script>
function showData(ret){
...
}
</script>
<script src="http://api.data.com/getInfo.php?callback=showData"></script>
所以总结来说JSONP是通过 script 标签加载数据的方式去获取数据当做 JS 代码来执行 提前在页面上声明一个函数,函数名通过接口传参的方式传给后台,后台解析到函数名后在原始数据上「包裹」这个函数名,发送给前端。换句话说,JSONP 需要对应接口的后端的配合才能实现。
下面我们来演示一下:



当前页面通过添加script标签,向数据接口页面发送请求获取数据并当作 提前在当前页面声明好的一个函数的参数 去执行并操作数据。
2. CORS
跨域资源共享(Cross-Origin Resource Sharing),是一种ajax跨域请求资源的方式,支持现代浏览器,IE10以上。
实现方式:当你使用 XMLHttpRequest 发送请求时,浏览器发现该请求不符合同源策略,会给该请求加一个请求头:Origin,后台进行一系列处理,如果确定接受请求则在返回结果中加入一个响应头:Access-Control-Allow-Origin; 浏览器判断该响应头中是否包含 Origin 的值,如果有则浏览器会处理响应,我们就可以拿到响应数据,如果不包含浏览器直接驳回,这时我们无法拿到响应数据。
CORS 的表象是让你觉得它与同源的 ajax 请求没啥区别,代码完全一样。
页面直接使用ajax发送请求

后端服务器发送响应时加上一个响应头

其中,res.setHeader('Access-Control-Allow-Origin','http://localhost:8080')
指的是后端允许的域名是 localhost: 8080;而 res.setHeader('Access-Control-Allow-Origin', '*')
则是允许任何人获取数据。
下面我们来演示一下(任何人都可以获取数据的情况):
同域

下面的截图显示的是 允许域名是 http://localhost: 8080
的用户跨域获取数据

跨域


3. 降域
场景:当前页面存在/嵌套不同域的iframe
只有在相同域名的条件下,才能去访问iframe里面的东西
不同域名的条件下,iframe里面的东西可以被加载但是不能获取和被操作



document.domain = 'jrg.com'
在两者中把二者降到 'jrg.com' 主域下,使二者之间可以实现相互访问前提是 域名要有相同的末尾段主域可降
4. postMessage
没有主域限制
嵌套跨域 iframe 的页面
// 当需要对iframe进行一定操作时
// 向当前iframe postMessage一个消息
// * 表示任何域下都可以接受
window.frames[0].postMessage(this.value,'*');
被嵌套的 iframe 本域的页面/接口
// 监听message事件(从中知道是否有人嵌套了本地iframe并向本地发送了消息)获取了消息数据并做对应的事情
// 可以定义出一些接口告知嵌套方要操作iframe可以发送消息
// 本地内部对消息有一些实现(通过嵌套方发送消息来修改一些东西)
window.addEventListener('message',function(e) {
$('.main input').value = e.data
console.log('b get:' + e.data);
});
首先,aa.html可以向bb.html postMessage消息

bb.html监听到message消息做出对应的事情


网友评论