跨域是指从一个域名的网页去请求另外一个域名的资源。好比从www.baidu.com 页面去请求 www.google.com 的资源。可是通常状况javascript
下不能这么作,它是由浏览器的同源策略形成的,是浏览器对JavaScript施加的安全限制。跨域的严格一点的定义是:只要 协议,域名,端口php
有任何一个的不一样,就被看成是跨域。html
所谓同源是指,域名,协议,端口均相同。这里说的js跨域是指经过js在不一样的域之间进行数据传输或通讯,好比用ajax向一个不一样的域请求数据,java
或者经过js获取页面中不一样域的框架中(iframe)的数据。jquery
总结:只要协议、域名、端口有任何一个不一样,都被看成是不一样的域。web
详细解释请看下图:ajax
假设如今有a.com和b.com两个域,若是没有这一安全策略,那么当用户在访问a.com时,a.com的一段脚本就能够在不加载b.com的页面而随意json
修改或者获取b.com上面的内容。这样将会致使b.com页面的页面发生混乱,甚至信息被获取,包括服务器端发来的session。这样的话,咱们的跨域
web世界将是一片混乱。也是由于浏览器的同源策略,保证来至不一样源的对象不会互相干扰,保证了咱们访问页面最基本的安全。浏览器
既然有安全问题,那为何又要跨域呢? 有时公司内部有多个不一样的子域,好比一个是location.company.com ,而应用是放在app.company
.com ,这时想从 app.company.com去访问 location.company.com 的资源就属于跨域。
CORS(Cross-Origin Resource Sharing
)跨域资源共享,定义了必须在访问跨域资源时,浏览器与服务器应该如何沟通。CORS
背后的基本思想
就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功仍是失败。
服务器端对于CORS
的支持,主要就是经过设置Access-Control-Allow-Origin
来进行的。若是浏览器检测到相应的设置,就能够容许Ajax进行跨域
的访问。
只须要在后台中加上响应头来容许域请求!在被请求的Response header中加入如下设置,就能够实现跨域访问了!
//指定容许其余域名访问
'Access-Control-Allow-Origin:*'//或指定域 //响应类型
'Access-Control-Allow-Methods:GET,POST'
//响应头设置
'Access-Control-Allow-Headers:x-requested-with,content-type'
jsonp采用script标签的src属性实现跨域获取资源。文档中的全部带“src”属性的标签均可以跨域加载资源,而不受同源策略的限制。
例如:在浏览器中<script>、<img>、<iframe>、<link>等标签均可以跨域加载资源,而不受同源策略的限制。这些带“src”属性的标签在
每次加载时,其实是由浏览器发起了一次GET请求。不一样于XMLHttpRequest的是,经过src加载的资源,浏览器限制了Javascript的权限,
使其不能读、写返回内容。
XMLHttpRequest受到同源策略的约束,不能跨域访问资源。但随着跨域请求的需求愈来愈迫切,W3C标准制定了XMLHttpRequest跨域访问
标准:它须要经过目标域返回的HTTP头来受权是否容许跨域行为。这一跨域方案的安全基础是信任“Javascript没法控制该HTTP头”。
JSONP由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数,而数据就是传入回调函数中的JSON数据。
JSONP的原理:经过script标签引入一个js文件,这个js文件载入成功后会执行咱们在url参数中指定的函数,而且会把咱们须要的json数据
做为参数传入。因此jsonp是须要服务器端的页面进行相应的配合的。(即用javascript动态加载一个script文件,同时定义一个callback
函数给script执行而已。)在js中,咱们直接用XMLHttpRequest
请求不一样域上的数据时,是不能够的。可是,在页面上引入不一样域上的js脚本
文件倒是能够的,jsonp正是利用这个特性来实现的。 例如:有个a.html页面,它里面的代码须要利用ajax获取一个不一样域上的json数据,
假设这个json数据地址是http://example.com/data.php,那么a.html中的代码就能够这样:
<script type="text/javascript">
function dosomething(jsondata){ //处理得到的json数据
} </script>
<script src="http://example.com/data.php?callback=dosomething"></script>
js文件载入成功后会执行咱们在url参数中指定的函数,而且会把咱们须要的json数据做为参数传入。因此jsonp是须要服务器端的页面进行
相应的配合的。
<?php $callback = $_GET['callback'];//获得回调函数名
$data = array('a','b','c');//要返回的数据
echo $callback.'('.json_encode($data).')';//输出
?>
最终,输出结果为:dosomething(['a','b','c']);
若是你的页面使用jquery,那么经过它封装的方法就能很方便的来进行jsonp操做了。
<script type="text/javascript"> $.getJSON('http://example.com/data.php?callback=?,function(jsondata)'){ //处理得到的json数据
}); </script>
jquery
会自动生成一个全局函数来替换callback=?
中的问号,以后获取到数据后又会自动销毁,实际上就是起一个临时代理函数的做用。$.getJSON
方法会自动判断是否跨域,不跨域的话,就调用普通的ajax
方法;跨域的话,则会以异步加载js文件的形式来调用jsonp
的回调函数。
JSONP的优势是:它不像XMLHttpRequest
对象实现的Ajax请求那样受到同源策略的限制;它的兼容性更好,在更加古老的浏览器中均可以运行,
不需要XMLHttpRequest或ActiveX的支持;而且在请求完毕后能够经过调用callback的方式回传结果。
JSONP的缺点则是:它只支持GET请求而不支持POST等其它类型的HTTP请求;它只支持跨域HTTP请求这种状况,不能解决不一样域的两个页面
之间如何进行JavaScript
调用的问题。
CORS与JSONP相比,无疑更为先进、方便和可靠。
一、 JSONP只能实现GET请求,而CORS支持全部类型的HTTP请求。
二、 使用CORS,开发者可使用普通的XMLHttpRequest发起请求和得到数据,比起JSONP有更好的错误处理。
三、 JSONP主要被老的浏览器支持,它们每每不支持CORS,而绝大多数现代浏览器都已经支持了CORS)。
浏览器都有一个同源策略,其限制之一就是第一种方法中咱们说的不能经过ajax的方法去请求不一样源中的文档。 它的第二个限制是浏览器中不
同域的框架之间是不能进行js的交互操做的。
不一样的框架之间是能够获取window对象的,但却没法获取相应的属性和方法。好比,有一个页面,它的地址是http://www.example.com/a.html
,
在这个页面里面有一个iframe
,它的src是http://example.com/b.html
, 很显然,这个页面与它里面的iframe
框架是不一样域的,因此咱们是没法
经过在页面中书写js代码来获取iframe
中的东西的:
<script type="text/javascript">
function test(){ var iframe = document.getElementById('ifame'); var win = document.contentWindow;//能够获取到iframe里的window对象,但该window对象的属性和方法几乎是不可用的
var doc = win.document;//这里获取不到iframe里的document对象
var name = win.name;//这里一样获取不到window对象的name属性
} </script>
<iframe id = "iframe" src="http://example.com/b.html" onload = "test()"></iframe>
这个时候,document.domain
就能够派上用场了,咱们只要把http://www.example.com/a.html
和 http://example.com/b.html
这两个页面的
document.domain都设成相同的域名就能够了。但要注意的是,document.domain的设置是有限制的,咱们只能把document.domain设置
成自身或更高一级的父域,且主域必须相同。例如:a.b.example.com 中某个文档的document.domain 能够设成a.b.example.com、
b.example.com 、example.com中的任意一个,可是不能够设成 c.a.b.example.com,由于这是当前域的子域,也不能够设成baidu.com,
由于主域已经不相同了。
1.在页面 http://www.example.com/a.html
中设置document.domain
:
<iframe id = "iframe" src="http://example.com/b.html" onload = "test()"></iframe> <script type="text/javascript"> document.domain = 'example.com';//设置成主域 function test(){ alert(document.getElementById('iframe').contentWindow);//contentWindow 可取得子窗口的 window 对象 } </script>
2.在页面 http://example.com/b.html
中也设置document.domain
:
<script type="text/javascript"> document.domain = 'example.com';//在iframe载入这个页面也设置document.domain,使之与主页面的document.domain相同 </script>
修改document.domain
的方法只适用于不一样子域的框架间的交互。
web sockets是一种浏览器的API,它的目标是在一个单独的持久链接上提供全双工、双向通讯。(同源策略对web sockets不适用)
web sockets原理:在js建立了web socket以后,会有一个HTTP请求发送到浏览器以发起链接。取得服务器响应后,创建的链接会使用HTTP升级
从HTTP协议交换为web sockt协议。
只有在支持web socket协议的服务器上才能正常工做。
var socket = new WebSockt('ws://www.baidu.com');//http->ws; https->wss socket.send('hello WebSockt'); socket.onmessage = function(event){ var data = event.data; }
建议使用CORS解决跨域问题