同源策略(SOP)
只有双方在协议、主机和端口号都完全匹配的情况下,才可以被授权访问。
跨域注意事项
所有的跨域都必须经过信息提供方允许,如果未经允许即可获得,那是浏览器同源策略出现漏洞。
1、通过脚本元素加载JSON(HTML脚本元素是可以规避SOP检查的),返回JSON对象,然后供页面使用。
2、通过回调函数替代全局变量的方式来传递JSON对象。需要在加载
var jsonp=document.createElement("script");
jsonp.onload=jsonp.onreadystatechange=function(){
if(!this.readyState||this.readyState==="loaded"||this.readyState==="complete"){
alert($("#demo").html());
jsonp.onload=jsonp.onreadystatechange=null;
}
}
jsonp.type="text/javascript";
jsonp.src="";
document.getElementsByTagName("head")[0].appendChild(jsonp);
JSONP的实现机制
JSONP全称json with padding,是为了解决跨域请求资源而产生的解决方案。
JSONP原理:虽然有同源策略的限制,但并不是html上所有资源都必须是同一个域,例如Google或者jQuery的CDN,在页面上我们可以引用这些代码,iframe、img、style、script等元素的src属性可以直接向不同域请求资源,JSONP正是利用script标签实现跨域请求资源。
局限性:JSONP只适用于HTTP的GET请求。
1、可以提交到服务器的数据量受限于浏览器的URL最大长度。
2、不能使用多用途表单来上传文件
3、很难使用基于REST的API
4、JSONP缺乏错误处理机制。调用回调函数不成功的时候,不会有任何提示。
5、JSONP请求总是异步的。当追加一个脚本元素到DOM或者提交表单时,浏览器会继续执行下一个任务,而不会等待响应返回。
6、不支持HTTPS
<script type="text/javascript">
window.callback=function (data) {
// 这是我们跨域得到的信息
console.log(data)
}
script>
//不一定服务器端真正有这个文件,可以动态生成。
<script src="http://coding.m.imooc.com/api.js">script>
适用于有相同顶级域名的主机。浏览器允许网站将主机部分更改为原始值的后缀。寄放在sub.example.com的页面可以将它的源设置为example.com.
每一个DOM的核心对象document都有一个domain属性,默认情况下,该值包含当前源的主机名部分。可以通过为这个属性重新赋值来改变当前文档的源。每个源只可以改变一次document.domain值。
当发生跨源HTTP请求时,支持CORS的浏览器会通过引入额外的Origin头信息来指定请求的源,这个头信息的值与同源策略使用的三个部分的值相同-协议、域名和端口
服务器的工作是检查头信息以确定是否接受该请求,如果一个请求被接受,它必须发回一个包含Access-Control-Allow-Origin,其值与发送的源相同的响应头。
response.setHeader("Access-Control-Allow-Origin","http://a.com");
response.setHeader("Access-Control-Allow-Headers","X-Request-With");
response.setHeader("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
// 接收跨域的cookie
response.setHeader("Access-Control-Allow-Credentials","true");
同源策略不允许跨域页面访问对方的属性。这是因为页面本身无法获知自身属性被谁访问。window.postMessage不再是直接访问一个文档的属性和方法,而是向文档发送信息后等待响应。这种方式要求双方建立一种双向的通信通道。window.postMessage(message,targetOrigin) 方法是HTML5新引进的特性,可以使用它来向其它的window对象发送消息,无论这个window对象是属于同源或不同源。这种方法不能和服务端交换数据,只能在两个窗口(iframe)之间交换数据
可以在想接受消息的目标窗口通过调用postMessage方法来发送消息。
在文档窗口创建的iframe如下:
var iframe=document.getElementById('my-iframe')
var win=iframe.documentWindow;
使用javascript打开的弹出窗口
var win=window.open()
当前窗口的父窗口
var win=window.parent
打开当前窗口的文档
var win=window.opener;
www.example.com中主动发起连接
window.οnlοad=function () {
window.frames[0].postMessage({name:'Cao'},"http://www.example.com");
window.addEventListener('message', function(event){
alert(event.data);
})
}
处于安全考虑,另一个域下的脚本中需要验证消息orgin来源后为http://www.example.com后再发送消息
window.addEventListener("message",function(event){
if(event.origin==="http://www.example.com"){
event.source.postMessage('hello world',event.origin);
}
})