js跨域是指经过js在不一样域之间进行相互通讯或者数据传输,只要协议,域名,端口号其中有一个不一样,就是跨域。下面总结一下我了解到的经常使用的跨域方法。javascript
jsonp
跨域js经过script标签引入一个外域的资源是不受限制的,jsonp就是利用这个原理,来实现跨域的。html
<script> function getPrice(data){ console.log(data); } </script> <script type="text/javascript" src="http://wsdetail.b2b.hc360.com/getSupplyPrice?callback=getPrice&bcid=47296567"></script>
callback是先后台约定的查询参数,服务器端返回一个能执行的js文件,这个js文件是调用callback对应的参数值即getPrice执行,而且返回对应的数据,咱们能够在getPrice方法里面来处理返回的数据,最终返回的结果以下html5
getPrice({ "data":{"priceType":"0","unit":"斤"}, "message":"价格获取成功!!!", "state":"1" })
jsonp
的原理就是这样,经过Script标签引入一个js文件,这个js文件加载成功会执行callback对应的指定方法,而且把咱们须要的数据做为参数传入,jsonp是须要服务器端配合的。java
$.ajax({ url:"http://wsdetail.b2b.hc360.com/getSupplyPrice", dataType:'jsonp', data:{bcid:"47296567"}, jsonp:'callback', jsonpCallback:'getPrice', success:function(data){ console.log(data); } })
下面是使用jquery的jsonp请求,jsonp只能是get请求,在jquery中jsonpCallback能够省略不写,jquery会自动生成一个全局函数替换callback=对应的全局函数,取到数据会自动销毁这个全局函数;jsonp参数用来替换“callback=?”中的callback
好比 {jsonp:'callbackOnload'},会生成'?callbackOnload=getPrice'传给服务器端;jquery
var xhr = new XMLHttpRequest(); if ('withCredentials' in xhr) { xhr.withCredentials = true; } xhr.open('post', 'https://api.growingio.com/v2/9c75e186a1a30142/web/action?stm=1499731328375', true); //true表示异步请求,若是是false则是同步请求, xhr.onreadystatechange = function () { if (xhr.readyState == 4) { if (xhr.status == 200) { var response = xhr.responseText; console.log(response) } } }; xhr.send('data');
XMLHttpRequest最关键部分在服务器部分 ,其实不管是否跨域,服务器都是能够获取上述请求的。问题的关键在于服务器的回应是否可以返回到浏览器。因此在服务器发送回应的时候,须要添加一个文件头。这个文件头的第一个参数是容许跨域,第二个参数是接受跨域的服务,web
Access-Control-Allow-Origin:http://a.text.com
其实与不一样的XMLHttpRequest还有一个小小的不一样,却很重要。同域内的XMLHttpRequest访问一般只有一次请求,而跨域的XMLHttpRequest有两次。ajax
第一次XMLHttpRequest请求,其method是OPTIONS,并不是前文定义的POST。这并非由JS代码控制的,而是浏览器来完成的操做。其做用是判断该请求是否可以被服务器所响应。json
第二次XMLHttpRequest请求才是真正的POST请求,包含了上传的文件内容。api
这里只是对 CORS 作一个简单的介绍,若是想更详细地了解其原理的话,能够看看下面这篇文章:跨域
下面介绍三种经过 iframe 跨域与其它页面通讯的方式。
postMessage 是H5新增的api可使用它来向其它的window对象发送消息,不管这个window对象是属于同源或不一样源,目前IE8+、FireFox、Chrome、Opera等浏览器都已经支持window.postMessage方法。
第一个参数是要发送的数据,第二个参数是接受消息的域,若是不想限定,可使用通配符'*'
<iframe src="http://b.text.com/index.html" width="200" height="200" id="iframEle" onload="load()"></iframe> <script> function load() { var _window = document.getElementById('iframEle').contentWindow; _window.postMessage('dfefe','http://b.text.com/index.html'); } window.onmessage=function (e) { alert(e.data) } </script>
b.text.com域名接受消息的时候须要经过监听onmessage事件,来获取传过来的消息,消息内容存储在事件对象的data属性中。
window.onmessage=function (e) { e=e||event; alert(e.data); window.parent.postMessage('1234',"*") }
document.domain
跨域一个页面嵌入一个外域的iframe页面,虽然两个窗体以前能获取彼此的window对象,可是却拿不到window上的属性和方法,例如一个http://a.text.com/index.html页面嵌入一个http://b.text.com/index.html的iframe
<iframe src="http://b.text.com/index.html" width="200" height="200" id="iframEle" onload="load()"></iframe> <script> function load() { var _window=document.getElementById('iframEle').contentWindow; _window.dialog(); } function parentAlert() { alert('我是父窗体的方法') } </script>
嵌入的窗体跟a.text.com的域名不一样,很明显是跨域的,虽然能获取到window对象,可是拿不到b页面的任何方法和属性。b页面能够用window.parent
拿到父窗体,可是也是一样不能拿到任何方法和属性。这个时候用document.domain能够解决这种问题
咱们在b页面设置document.domain,在a页面也设置document.domain,document.domain设置也是有限制的,咱们只能把domain设置成自身或者更高一级的父域。主域必须相同
document.domain='text.com'; function dialog() { alert('ifram里面的方法') } window.parent.parentAlert()
咱们在a页面也设置一下domain, document.domain='text.com';
两个窗体之间能够正常通讯了,这就是经过domain跨域获取数据,这种方式只适合两个窗体以前,不适合ajax请求;
window.name
属性window对象有一个name属性,在一个窗口生命周期内,全部载入的页面共享这个name属性,而且都有对这个name的读写权限。好比有一个页面 http://a.text.com/index.html
window.name='我是index页面设置的name属性'; setTimeout(function () { window.location.href='http://b.text.com/index.html'; },3000)
3秒后载入了b页面,在b页面咱们获取window.name,成功的获取到了index页面设置的window.name的值,须要注意的是window.name只能是字符串形式,大小2M左右,下面就来看看具体怎样经过window.name跨域获取数据
在http://my.b.text.com/index.html页面嵌入一个iframe,
var _iframe=document.createElement('iframe'); _iframe.src='http://b.text.com/index.html'; _iframe.style.display='none'; document.body.appendChild(_iframe); _iframe.onload=function () { _iframe.src='about:blank;'; _iframe.onload=function () { alert(_iframe.contentWindow.name); } }
http://b.text.com/index.html页面设置window.name
window.name='iframe数据'
在http://my.b.text.com/index.html页面请求http://b.text.com/index.html页面的数据,咱们能够在页面创建一个iframe,src指向请求的地址,利用iframe的跨域能力 在请求的页面设置window.name的值。 可是因为 my.b.text.com 页面和该页面 iframe 的 src 若是不一样源的话,则没法操做 iframe 里的任何东西,因此就取不到 iframe 的 name 值,因此咱们须要在 b.text.com 加载完后从新换个 src 去指向一个同源的 html 文件,或者设置成 'about:blank;'改变iframe的src指向后,这个时候在监听iframe的onload属性,就能够获取到iframe的window.name属性了;