说到跨域,咱们就不得不先提一下同源。javascript
同源是浏览器的一种安全策略,所谓同源是指,域名,协议,端口彻底相同,而不一样源就是跨域。也就是说咱们若是域名,协议,端口只要有一个不是不一样的那么就是跨域。php
举个例子说:http://www.example.com/html
http://api.example.com/detail.html 不一样源 域名不一样 https//www.example.com/detail.html 不一样源 协议不一样 http://www.example.com:8080/detail.html 不一样源 端口不一样 http://api.example.com:8080/detail.html 不一样源 域名、端口不一样 https://api.example.com/detail.html 不一样源 协议、域名不一样 https://www.example.com:8080/detail.html 不一样源 端口、协议不一样 http://www.example.com/detail/index.html 同源 只是目录不一样
经过上面的例子,相信你们都对同源和跨域有了必定的了解。浏览器出于安全考虑,同源策略不容许跨域调用其余页面的对象。可是安全限制的同时也给咱们使用iframe或者获取其余服务器上的接口数据带来了很多的麻烦。前端
由于咱们在所不免的会须要调用其余服务器的接口,因此提供了一下几个跨域的方案。html5
前面咱们说到浏览器的同源策略限制了不一样源的iframe之间进行的DOM操做,可是须要说明的一点是,在不一样的iframe之间(父子或同级)是可以获取到彼此window对象的。java
document.domain解决了在顶级域名相同的状况下可是域名不彻底相同的跨域问题.jquery
好比:咱们有一个页面它的地址是: http://www.study.com/domain.html 在这个页面中有一个有一个iframe,它的src是http://api.study.com/domain.html,代码以下web
<body> <p>我是父窗口study.com的内容</p> <iframe id="iframe" src="http://api.study.com/domain.html" frameborder="0"> </iframe> <script> // 这种状况适合 顶级域名相同的状况 document.domain = 'study.com'; var iframe = document.getElementById('iframe'); iframe.onload = function () { var contentWin = iframe.contentWindow; contentWin.document.getElementById('txt').style.color = 'red'; } </script> </body>
很显然这个页面和它里面的iframe来自不一样的域,咱们默认是没法相互操做对方的DOM元素的,可是若是咱们都将两个页面的document.domain 设为相同的域名即:document.domain = 'study.com'就能够操做对方DOM元素了。iframe页面的代码以下ajax
<body> <p id="txt">我是api.study.com域下的一个页面</p> <script> document.domain = 'study.com'; // 访问父级 top.document.getElementsByTagName('p')[0].style.color = 'red'; </script> </body>
须要说明的是:document.domain的设置是有限制的,咱们只能把document.domain设置成自身或更高一级的父域,且顶级域名必须相同。 例如:a.b.study.com 中的某个页面的document.domain 能够设成a.b.study.com、b.study.com 、study.com中的任意一个,可是不能够设成 c.a.b.study.com,由于这是当前域的子域,也不能够设成baidu.com,由于顶级域名已经不相同了。json
在实现了两个页面的DOM元素访问也就至关于实现了两个页面之间的数据传递,这个就须要咱们一块儿发散思惟了。
咱们前面说到在不一样的iframe之间(父子或同级)是可以获取到彼此window对象的。咱们能够经过window.name实现的跨域数据传输。window对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的全部页面都是共享一个window.name的,每一个页面对window.name都有读写权限,window.name是持久存在一个窗口载入过的全部页面中的,并不会因新页面的的载入而进行重置。
效果实现: 咱们须要准备三个页面:
www.study.com/name.html //应用页面。
<body> <!-- setp 1 --> <iframe id="iframe" src="http://api.study.com/name.html" frameborder="0"> </iframe> <button id="btn">获取数据</button> <script> var iframe = document.getElementById('iframe'); // 将数据填加到name上了 iframe.contentWindow.name = 100; iframe.onload = function () { this.src = 'proxy.html'; this.onload = null; } var btn = document.getElementById('btn'); btn.onclick = function () { var text = iframe.contentWindow.name; document.write('<p>我是从api.study.com中获得值' + text + '</p>'); } </script> </body>
www.study.com/proxy.html //代理文件,通常是一个没有任何内容的html文件,须要和应用页面在同一域下。在应用页面动态建立iframe
api.study.com/name.html //应用页面须要获取数据的页面,可称为数据页面。
<body> <p id="txt">我是api.study.com域下的一个页面</p> <script> window.name = 400; </script> </body>
你们都知道location是javascript里边BOM中管理地址栏的内置对象,好比location.href就管理页面的url,用location.href=url就能够直接将页面重定向url。而location.hash则能够用来获取或设置页面的标签值。好比http://domain/#admin的location.hash="#admin"。
它的原理和window.name有些相似都须要经过一个同源文件做为代理文件,和window.name同样咱们也须要准备三个页面。
www.study.com/hash.html //应用页面。
<body> <script type="text/javascript"> function getData(url, fn) { var iframe = document.createElement('iframe'); iframe.style.display = 'none'; iframe.src = url; iframe.onload = function() { fn(iframe.contentWindow.location.hash.substring(1)); window.location.hash = ''; document.body.removeChild(iframe); }; document.body.appendChild(iframe); } // get data from server var url = 'http://api.study.com/hash.php'; getData(url, function(data) { var jsondata = JSON.parse(data); console.log(jsondata.name + ' ' + jsondata.age); }); </script> </body>
www.study.com/proxy.html //代理文件,须要和应用页面在同一域下。
api.study.com/hash.php //应用页面须要获取数据的页面,可称为数据页面。
<?php // 若是有必要则进行数据处理 $_GET['..'] // code // 返回的数据 $data = '{\"name\":\"zs\",\"age\":10}'; echo "<script> window.location = 'http://localhost/proxy.html' + '#' + \"$data\"; </script>"; ?>
window.postMessage(message,targetOrigin) 方法是html5新引进的特性,可使用它来向其它的window对象发送消息,不管这个window对象是属于同源或不一样源,目前IE8+、FireFox、Chrome、Opera等浏览器都已经支持window.postMessage方法。
postMessage(data,origin)方法接受两个参数
1.data:要传递的数据,html5规范中提到该参数能够是JavaScript的任意基本类型或可复制的对象,然而并非全部浏览器都作到了这点儿,部分浏览器只能处理字符串参数,因此咱们在传递参数的时候须要使用JSON.stringify()方法对对象参数序列化,在低版本IE中引用json2.js能够实现相似效果。
2.origin:字符串参数,指明目标窗口的源,协议+主机+端口号[+URL],URL会被忽略,因此能够不写,这个参数是为了安全考虑,postMessage()方法只会将message传递给指定窗口,固然若是愿意也能够建参数设置为"*",这样能够传递给任意窗口,若是要指定和当前窗口同源的话设置为"/"。
此次咱们只须要两个页面便可
www.study.com/postMessage.html
<body> <iframe id="iframe" src="http://api.study.com/postmessage.html" frameborder="0"> </iframe> <script> var iframe = document.getElementById('iframe'); iframe.onload = function () { // 向哪一个域下传值 iframe.contentWindow.postMessage('red', 'http://api.study.com'); } </script> </body>
api.study.com/possMessage.html
<body> <p id="txt">我是api.study.com域下的一个页面</p> <script> window.addEventListener('message', function(ev) { document.getElementById('txt').style.color = ev.data; }); </script> </body>
全名为:JSON with Padding
咱们都知道link 、 script 、img 标签都有跨域的能力,而jsonp的本质就是利用了script标签的可跨域的特性,由服务端返回一个预先定义好的Javascript函数的调用,而且将服务器数据以该函数参数的形式传递过来,此方法须要先后端配合完成。
前端页面:www.study.com/jsonp.html
<script> function fuck(data){ var data = JSON.parse(data); console.log(data); } </script> <script src="http://api.study.com/jsonp.php?callback=fuck"></script>
后台页面api.study.com/jsonp.php
<?php header('Content-Type:text/html;charset=utf-8'); $callback = $_GET['callback']; $json = '{"name":"xjj","age":"10"}'; echo $callback."('$json')"; ?>
在咱们经常使用的jquery中的调用时集合在了ajax方法中,
将设置dataType值为jsonp即开启跨域访问
jsonp 能够指定服务端接收的参数的“key”值,默认为callback
jsonpCallback 能够指定相应的回调函数,默认自动生成
前端调用 www.study.com/jquery_jsonp.html
$.ajax({ type:'get', url:'http://api.study.com/jquery_jsonp.php', dataType:'jsonp', jsonp:'callback', success:function(data){ console.log(data); } });
后台页面 api.study.com/jquery_jsonp.php
<?php header('Content-Type:text/html;charset=utf-8'); /*处理业务逻辑 返回数据给第三方过的的接口*/ $callback = $_GET['callback']; $json = '{"name":"xjj","age":"18"}'; echo $callback.'('.$json.')'; ?>
当前几乎全部的浏览器(Internet Explorer 8+, Firefox 3.5+, Safari 4+和 Chrome 3+)均可经过名为跨域资源共享(Cross-Origin Resource Sharing)的协议支持ajax跨域调用。
假设您的页面在 www.study.com 上了,而您想要从 www.learn.com 提取数据。通常状况下,若是您尝试进行这种类型的 AJAX 调用,请求将会失败,而浏览器将会出现“源不匹配”的错误。利用 CORS,www.learn.com 服务端只需添加一个HTTP Response头,就能够容许来自 www.study.com 的请求:
Access-Control-Allow-Origin: http://example.com Access-Control-Allow-Credentials: true(可选)
可将 Access-Control-Allow-Origin 添加到某网站下或整个域中的单个资源。要容许任何域向你提交请求,请设置以下:
Access-Control-Allow-Origin: * Access-Control-Allow-Credentials: true(可选)
启用开发人员工具后,您就会在响应中看到 Access-Control-Allow-Origin 。
若是服务器端已启用了 CORS,那么提交跨域请求就和普通的 XMLHttpRequest 请求没什么区别。例如,如今 example.com 能够向 www.example2.com 提交请求了:
$.ajax({ type:'get', url:'http://api.study.com/CORS.php', dataType:'jsonp', success:function(data){ console.log(data); } });
CORS在移动终端支持的不错,能够考虑在移动端全面尝试;PC上有不兼容和没有完美支持。
CORS提供了一种跨域请求方案,但没有为安全访问提供足够的保障机制,若是你须要信息的绝对安全,不要依赖CORS当中的权限制度,应当使用更多其它的措施来保障。