特别注意两点:
1、如果是协议和端口造成的跨域问题“前台”是无能为力的
2、在跨域问题上,域仅仅是通过“URL的首部”来识别而不会去尝试判断相同的ip地址对应着两个域或两个域是否在同一个ip上。比如上面的,http://www.a.com/a.js和http://70.32.92.74/b.js。虽然域名和域名的ip对应,不过还是被认为是跨域。
“URL的首部”指window.location.protocol +window.location.host。其中,
window.location.protocol:指含有URL第一部分的字符串,如http:
window.location.host:指包含有URL中主机名:端口号部分的字符串.如//www.cenpok.net/server/
常用的几种跨域处理方法:
1、JSONP
2、CORS策略
3、document.domain+iframe的设置
4、HTML5的postMessage
5、使用window.name来进行跨域
跨域的原理解析及实现方法
1、JSONP(JSON with padding)
原理 :
我们知道,在页面上有三种资源是可以与页面本身不同源的。它们是:js脚本,css样式文件,图片,像淘宝等大型网站,肯定会将这些静态资源放入cdn中,然后在页面上连接,如下所示,所以它们是可以链接访问到不同源的资源的。
1)<script type="text/javascript" src="某某cdn地址" ></script>
2)<link type="text/css" rel="stylesheet" href="某个cdn地址" />
3)<img src="某个cdn地址" alt=""/>
而jsonp就是利用了script标签的src属性是没有跨域的限制的,从而达到跨域访问的目的。因此它的最基本原理就是:动态添加一个<script>标签来实现。
实现方法:
这里是使用ajax来请求的,看起来和ajax没啥区别,其实还是有区别的。
ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加<script>标签来调用服务器提供的js脚本。
$.ajax({ url:"http://crossdomain.com/services.php", dataType:"jsonp", data:"", jsonp:"callback", success:function(result) { // some code} });上面的代码中,callback是必须的,callback是什么值要跟后台拿。获取到的jsonp数据格式如下:
flightHandler({"code": "CA1998","price": 1780,"tickets": 5});jsonp的全称为json with padding,上面的数据中,flightHandler就是那个padding.
var xhr = new XMLHttpRequest(); xhr.open("GET", "/hfahe", true); xhr.send(); // 这里的“/hfahe”是本域的相对路径。如果我们要使用CORS,相关Ajax代码可能如下所示:
var xhr = new XMLHttpRequest(); xhr.open("GET", "http://blog.csdn.net/hfahe", true); xhr.send(); // 请注意,代码与之前的区别就在于相对路径换成了其他域的绝对路径,也就是你要跨域访问的接口地址。服务器方面
//http://www.example.com/a.html<html><head><title>A页面</title><script type="text/javascript" src="jquery.js"></script></head><body><div>A页面</div><iframe id="iframe" src="http://example.com/b.html" style="display:none;"></iframe> // 相当于用一个隐藏的iframe来做代理<script>$(function(){try{document.domain = "example.com"; //这里将document.domain设置成一样}catch(e){}$("#iframe").load(function(){var iframe = $("#iframe").contentDocument.$;ifram.get("http://example.com/接口",function(data){});});});</script><body></html>在页面 http://example.com/b.html 中也设置document.domain,而且这也是必须的,虽然这个文档的domain就是example.com,但是还是必须显示的设置document.domain的值:
//http://example.com/b.html<html><head><title>B页面</title><script type="text/javascript" src="jquery.js"></script></head><body><div>B页面</div><script>$(function(){try{document.domain = "example.com"; //这里将document.domain设置成一样}catch(e){}});</script></body></html>这里有个注意点,就是在A页面中,要等iframe标签完成加载B页面之后,再取iframe对象的contentDocument,否则如果B页面没有被iframe完全加载,在A页面中通过contentDocument属性就取不到B页面中的jQuery对象。
var iframe = document.getElementById("my-iframe");var win = iframe.documentWindow;2、JavaScript打开的弹窗:
var win = window.open();
var win = window.parent;
var win = window.opener();
win.postMessage(msg, targetOrigin);
var onmessage = function (event) {var data = event.data;var origin = event.origin;//do someing};if (typeof window.addEventListener != "undefined") {window.addEventListener("message", onmessage, false);} else if (typeof window.attachEvent != "undefined") {//for iewindow.attachEvent("onmessage", onmessage);}message事件监听函数接收一个参数,Event对象实例,该对象有三个属性:
<!-- 这个是 http://test.com/index.html 页面 --><div><!-- 要给下面的页面传一个妹子过去 --><iframe id="child" src="http://lsLib.com/lsLib.html"></iframe> </div><script type="text/javascript">window.onload=function(){window.frames[0].postMessage("苍老师","http://lslib.com");}</script>http://lslib.com/lslib.html --> 接收消息的页面
<!-- 这个是 http://lslib.com/lslib.html 页面 --><script type="text/javascript">window.addEventListener("message",function (e) {console.log(e.origin,e.data);alert("收到妹子一枚:"+e.data);});</script>优缺点:
// data.htmlwindow.name="苍老师"; //可以是其他类型的数据,比如数组,对象等等http://www.a.com/main.html //应用页面的代码如下:
<!-- main.html -->var iframeData;var state = 0;//开关变量var iframe = document.createElement("iframe"); //创建iframevar loadfn = function() {if (state === 1) {iframeData = iframe.contentWindow.name; // 读取数据alert("获取到了iframe传过来的妹子"+iframeData);}else if (state === 0) { state = 1; iframe.contentWindow.location = "http://www.a.com/other.html"; //这里是代理页面 other.html /** 这里说明一下: 由于iframe的location改变了,相当于重新载入页面(这是iframe的性质决定的),于是重新执行loadfn方法。 由于当iframe的页面跳到其他地址时,其window.name值保持不变,并且此时开关变量 state已经变为1, 于是就可以获取到window.name值,也就达到了跨域访问的目的了。**/};}iframe.src = "http://www.b.com/data.html"; //这是是数据页面,data.htmlif (iframe.attachEvent) {iframe.attachEvent("onload", loadfn);} else {iframe.onload = loadfn;}document.body.appendChild(iframe);3、获取数据以后销毁这个iframe,释放内存;这也保证了安全(不被其他域frame js访问)。
iframe.contentWindow.document.write(""); iframe.contentWindow.close(); document.body.removeChild(iframe);优缺点: